Introduction
Support Vector Machines (SVM) are a powerful and versatile set of
supervised learning algorithms widely used for classification,
regression, and outlier detection tasks. It is particularly well-suited
for problems involving complex, high-dimensional data and is robust
against overfitting.
Binary Classification: SVM is widely used to
classify data into two distinct classes by finding the best decision
boundary (hyperplane) that separates the classes with the maximum
margin.
Multi-class Classification: SVM can handle
multi-class problems by combining multiple binary classifiers using
techniques like one-vs-one or one-vs-all.
Regression (SVR - Support Vector Regression): SVM
can predict continuous outputs by finding a hyperplane that approximates
the target variable within a margin of tolerance.
Outlier Detection: SVM can detect anomalies by
identifying data points that deviate significantly from the main
distribution.
SVM is a distribution-free method for both classification and
regression. Linear support vector machines are commonly used in
practice. However, depending on the complexity of the practical
problems, non-linear SVMs are also frequently used.
This module focuses on linear SVM and its applications in regression
and classification. The kernel SVM will also be introduced to handle
nonlinear classification and regression problems.
How SVM Works?
To help gain an intuitive understanding of SVM, we consider the
binary classification task of SVVM in two-dimensional feature space
using a subset of the well-known iris data set.
# iris data
iris0 <- iris[c(1:50, 101:150), c("Sepal.Length", "Sepal.Width","Species" )]
iris0 <-iris0[which(iris0$Sepal.Length> 5 & iris0$Sepal.Width>2.5),]
## support vectors
cvData = data.frame(xx=c(5.5,5.4,5.6,6.2),
yy=c(3.5,3.4,2.8,3.4),
pt=c("A", "B", "C", "D"))
##
svmgg <- ggplot(data = iris0, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) +
geom_point(shape=19, size=3) +
geom_point(data =cvData, aes(x=xx, y=yy), shape =19, size=2, color = "darkred") +
annotate("text",
x = c(5.5,5.4,5.6,6.2)+0.04,
y = c(3.5,3.4,2.8,3.4)-0.04,
label = c("A", "B", "C", "D"),
size = 3.3,
color = "darkred") +
scale_x_continuous(minor_breaks = seq(5, 8, 0.1)) +
scale_y_continuous(minor_breaks = seq(2.5, 4.5, 0.1)) +
geom_abline(intercept = 1,
slope = 0.4,
color="lightseagreen",
linetype=1,
size=0.5) +
geom_abline(intercept = -6,
slope = 1.7,
color="indianred3",
linetype=1,
size=0.5) +
geom_abline(intercept = -2.8,
slope = 1,
color="blue",
linetype=2,
size=0.75) +
geom_label( label="L1: y = x - 2.8",
x=7.3,
y=4.4,
label.padding = unit(0.25, "lines"), # Rectangle size around label
label.size = 0.15,
color = "blue",
fill="white" ) +
geom_abline(intercept = -2,
slope = 1,
color="blue",
linetype=2,
size=0.75) +
geom_label( label="L2: y = x - 2",
x=6.1,
y=4.1,
label.padding = unit(0.25, "lines"), # Rectangle size around label
label.size = 0.15,
color = "blue",
fill="white" ) +
# margin
geom_segment(x = 5.9, y = 3.9, xend = 6.3, yend = 3.5,
arrow = arrow(length = unit(0.02, "npc"), ends = "both"),
color = "darkgreen", size = 0.85) +
# linear decision boundary
geom_abline(intercept = -2.4,
slope = 1,
color="darkred",
linetype=1,
size=0.75) +
geom_label( label="L3: y = x - 2.4",
x=6.6,
y=4.25,
label.padding = unit(0.25, "lines"), # Rectangle size around label
label.size = 0.15,
color = "darkred",
fill="white" ) +
# annotation
annotate(geom = "text", x = 6.05, y = 3.85,
label = "Margin",
color = "darkgreen",
size = 3.1,
angle = -42) +
#
geom_label( label="L4: y = 0.4x + 1",
x=7.5,
y=4,
label.padding = unit(0.25, "lines"), # Rectangle size around label
label.size = 0.1,
color = "lightseagreen",
fill="white" ) +
geom_label( label="L5: y = 1.7x - 6",
x=6.1,
y=4.4,
label.padding = unit(0.25, "lines"), # Rectangle size around label
label.size = 0.05,
color = "indianred3",
fill="white" ) +
ggtitle("Key Terms in SVM") +
theme( axis.line = element_line(size = .5, color = "red"),
panel.grid.major = element_line(color = "gray", size = (.2)),
panel.grid.minor = element_line(size = (0.2), color = "gray"),
panel.background = element_blank(),
plot.margin = unit(c(1,0,1,1), "cm"),
plot.title = element_text(hjust=0.5,
vjust = 5,
family = "sans",
size = 16),
legend.position = c(0.9, 0.45),
legend.background = element_rect(fill="white",
size=0.5,
linetype="solid",
colour ="darkblue"),
aspect.ratio=0.55)
svmgg

#ggplotly(svmgg)
Feature Space: A feature space is spanned by a set
of feature variables (independent variable, predictor variable). In the
above figure. The dependent variable (not considered as a
feature variable) is Species. Sepal.Length and
Sepal.Width are the two feature variables. The
two-dimensional coordinate system shown in the above figure is called
two-dimensional feature space. The dimension of feature space is
equal to the number of (uncorrelated) feature variables.
Hyperplane: The hyperplane is a
decision boundary that separates classes in the feature space. In the
above 2D figure, the hyperplane is any straight
line that separates the two Species. In general,
the dimension of a hyperplane in an n-dimensional
feature space is \(n-1\).
Margin: The margin is the distance between the two
parallel hyper-planes that separate the two classes of
the response variable. In the above figure, the parallel hyperplanes
\(L1\) and \(L2\) completely separate the two
classes.
Support Vectors: Support vectors are the points
closest to the decision boundary,
not on it. These points are
located on the margins that define the maximum-margin
hyperplane. The decision boundary itself is positioned
equidistant between these margins, and the support vectors are the data
points that determine the margin width.
SVM Algorithm: Maximize the margin while minimizing
misclassification errors.
Handing Categorical
Features
The examples and illustrations of SVM discussed earlier are based on
numerical features. When dealing with categorical features, we need to
convert them into numerical representations. Below are some common
techniques for handling categorical features in SVM.
One-Hot Encoding
One-hot encoding converts each categorical feature into a binary
vector, where each category is represented as a binary column.
An illustrative example in R:
# Load necessary library
#library(e1071) # For SVM
#library(caret) # For data preprocessing
# Example dataset
data <- data.frame(
feature1 = c("A", "B", "A", "C"),
feature2 = c("X", "Y", "X", "Z"),
target = c(1, 0, 1, 0)
)
# One-hot encoding
dummy <- dummyVars(" ~ .", data = data)
data_encoded <- data.frame(predict(dummy, newdata = data))
# View encoded data
print(data_encoded)
feature1A feature1B feature1C feature2X feature2Y feature2Z target
1 1 0 0 1 0 0 1
2 0 1 0 0 1 0 0
3 1 0 0 1 0 0 1
4 0 0 1 0 0 1 0
# Train SVM
#svm_model <- svm(target ~ ., data = data_encoded, kernel = "linear")
#summary(svm_model)
One-hot encoding is the most common method but can lead to high
dimensionality for features with many categories.
Label Encoding
Label encoding assigns a unique integer to each category. This is
useful for ordinal categorical features.
An illustrative example in R:
# Example dataset
data <- data.frame(
feature1 = c("Low", "Medium", "High", "Low"),
feature2 = c("Small", "Large", "Medium", "Small"),
target = c(1, 0, 1, 0)
)
# Label encoding
data$feature1 <- as.numeric(factor(data$feature1, levels = c("Low", "Medium", "High")))
data$feature2 <- as.numeric(factor(data$feature2, levels = c("Small", "Medium", "Large")))
# View encoded data
print(data)
feature1 feature2 target
1 1 1 1
2 2 3 0
3 3 2 1
4 1 1 0
# Train SVM
#svm_model <- svm(target ~ ., data = data, kernel = "linear")
#summary(svm_model)
Label encoding is suitable for ordinal data but may introduce
unintended ordinality for nominal data.
Frequency
Encoding
Frequency encoding replaces each category with its frequency in the
dataset.
An illustrative example in R:
# Example dataset
data <- data.frame(
feature1 = c("A", "B", "A", "C"),
feature2 = c("X", "Y", "X", "Z"),
target = c(1, 0, 1, 0)
)
# Frequency encoding
freq_encoding <- function(column) {
freq <- table(column)
return(as.numeric(freq[column]))
}
data$feature1 <- freq_encoding(data$feature1)
data$feature2 <- freq_encoding(data$feature2)
# View encoded data
print(data)
feature1 feature2 target
1 2 2 1
2 1 1 0
3 2 2 1
4 1 1 0
# Train SVM
#svm_model <- svm(target ~ ., data = data, kernel = "linear")
#summary(svm_model)
Frequency encoding and target encoding are useful for reducing
dimensionality but may lead to overfitting if not regularized.
Target Encoding
Target encoding replaces each category with the mean of the target
variable for that category. This is useful for supervised learning
tasks.
An illustrative example in R:
# Example dataset
data <- data.frame(
feature1 = c("A", "B", "A", "C"),
feature2 = c("X", "Y", "X", "Z"),
target = c(1, 0, 1, 0)
)
# Target encoding
target_encoding <- function(column, target) {
mean_target <- tapply(target, column, mean)
return(mean_target[column])
}
data$feature1 <- target_encoding(data$feature1, data$target)
data$feature2 <- target_encoding(data$feature2, data$target)
# View encoded data
print(data)
feature1 feature2 target
1 1 1 1
2 0 0 0
3 1 1 1
4 0 0 0
# Train SVM
#svm_model <- svm(target ~ ., data = data, kernel = "linear")
#summary(svm_model)
SVM Classification
Algorithms
Hard margin and soft margin are indeed core concepts in Support
Vector Machines (SVM), and they determine how strictly the model
enforces the separation of data points into their respective classes.
They are central to understanding how SVMs handle linearly separable and
non-linearly separable data.
For ease of presentation, we use the linear SVM for classification as
an example to explain the concept of soft and hard margins and the
formulation of SVM. Note that the distance between two parallel
hyperplanes in a k-dimensional space, denoted by
\[
L_1: \ a_1 x_1 +a_2 x_2 + \cdots + a_k x_k + d_1 = 0
\] and
\[
L_2: \ a_1 x_1 +a_2 x_2 + \cdots + a_k x_k + d_2 = 0,
\]
is given by
\[
|L_1L_2| = \frac{|d_2-d_1|}{\sqrt{a_1^2 + a_2^2 + \cdots + a_k^2}}
\]
Hard Margin SVM
Without loss of generality, we consider the linear separation problem
in 2 dimensional feature space.
The goal is to find the hyperplane that maximizes the margin (the
distance between the two parallel hyperplanes and the
nearest data points from each class) while ensuring that all data points
are correctly classified. In the two dimensional feature space, the two
parallel hyperplanes are denoted by respectively
\[
w_1x_1 + w_2 x_2 + b = +1 \ \ \text{and} \ \ w_1x_1 + w_2x_2 + b =
-1.
\]
The coefficients of \(x_1\) and
\(x_2\) of two expressions are
identical because they are parallel. With the above non-standard
notation, the hyperplane \(w_1x_1 + w_2 x_2 + b = +1\) is closer to
the group with label \(y =
+1\), while \(w_1x_1 + w_2 x_2
+ b = -1\) is closer to the group with label \(y = -1\). Consequently, \(w_1x_1 + w_2 x_2 + b = +1\) is referred to
as the Positive Margin Hyperplane and \(w_1x_1 + w_2 x_2 + b = -1\) as the
Negative Margin Hyperplane.
If we introduce the following column vector notations
\[
\mathbf{w} = \begin{bmatrix}
w_1 \\
w_2
\end{bmatrix} \ \ \text{and} \ \
\mathbf{x} = \begin{bmatrix}
x_1 \\
x_2
\end{bmatrix},
\]
we can re-express in the following vector form
\[
\mathbf{w^Tx} + b = 1 \ \ \text{and} \ \ \mathbf{w^Tx} + b = -1.
\]
Using the above notations, we summarize the positive and negative
hyperplanes in the following figure.
include_graphics("img/HardMargin.png")

Based on the formula of distance between two parallel lines (i.e.,
the 2D hyperplanes), the problem of maximizing the margin \(2/||\mathbf{w}||_2\) is expressed in the
following equivalent expressions
\[
\max_{\mathbf{w},b}\frac{2}{||\mathbf{w}||^2_2} \rightarrow
\max_{\mathbf{w},b}\frac{1}{||\mathbf{w}||^2_2} \rightarrow
\min_{\mathbf{w},b}||\mathbf{w}||^2_2.
\]
That is, the above optimization problem is to estimate \(\mathbf{w} = (w_1, w_2)\) and \(b\) that maximize the
margin \(2/||\mathbf{w}||_2\) or
minimize \(||\mathbf{w}||_2\). This optimization will
be performed using software programs such as R function
svm() in R library MASS.
Once \(\mathbf{w} = (w_1, w_2)\) and
\(b\) are estimated from the data, the
center hyperplane between the two parallel hyperplanes,
the desired decision boundary - \(\mathbf{w^Tx} + b = 0\) , is
uniquely determined.
Finally, the objective function of maximizing hard-margin in SVM is
given by
\[
\min_{\mathbf{w},b} ||\mathbf{w}||^2
\]
subjecting to the constraint that all data points are correctly
classified
\[
y_i(\mathbf{w}^T\mathbf{x}_i + b) \ge 1 \ \ \text{for any} \ \ i.
\]
where \(y_i\) is the label of \(i\)-th data point taking values \(+1\) or \(-1\).
Soft Margin:
C-classification
Soft margin SVM is used when the data is not linearly
separable or contains noise. It allows for
some misclassification by introducing slack variables (\(\xi_i\)) that measure the degree
of misclassification for each data point. The goal is to maximize
the margin while minimizing the sum of these slack variables.
include_graphics("img/SoftMargin.png")

We can see from the above figure that \(0
< \xi_1 < 1\) and \(\xi_2, \xi_3
> 1\).
The estimation of the unknown parameters in the SVM algorithm is the
following optimization.
\[
\min_{\mathbf{w},b} \left( ||\mathbf{w}||^2 + C\sum_{i=1}^n \xi_i\right)
\]
Subject to the constraint that all data points are correctly
classified
\[
y_i(\mathbf{w}^T\mathbf{x}_i + b) \ge 1 - \xi_i \ \ \text{for any} \ \
i.
\]
where \(\xi_i \ge 0\) and \(y_i\) is the label of \(i\)-th data point taking values \(+1\) or \(-1\). \(C\) is a regularization parameter that
controls the trade-off between maximizing the margin and minimizing the
classification error.
The slack variable \(xi_i\) is a measure of how much a
point violates the hard margin constraint.
Correctly classified points outside the margin will have \(\xi_i = 0\).
Correctly classified points within the margin will have \(0 < \xi_i < 1\).
Misclassified points will have \(\xi_i
>1\).
The support vector machine based on maximizing soft margin is also
called C-Classification to highlight the importance of
the regularization parameter \(C\).
The regularization parameter \(C\)
in SVM is indeed a hyperparameter that needs to be
tuned to achieve the best performance for a specific dataset. It is not
something that is learned during training but rather set before training
begins.
- \(C\) controls
the penalty for misclassified or margin-violating data points in soft
margin SVM.
- A larger \(C\)
imposes a higher penalty for misclassifications, leading to a narrower
margin and stricter classification (closer to hard margin
SVM).
- A smaller \(C\) allows more misclassifications,
resulting in a wider margin and a more flexible model.
Proper tuning of \(C\) is crucial
because it directly influences the trade-off between maximizing the
margin and minimizing classification errors.
\(\nu\) - Classification
Unlike C-classification SVM in which the trade-off between maximizing
the margin and minimizing misclassification errors is controlled by the
regularization parameter \(C\), In
\(\nu\)-SVM, the trade-off is
controlled by the parameter \(\nu\).
The objective function is defined as
\[
\min_{\mathbf{w}, b, \mathbf{\xi}, \rho} \left( ||\mathbf{w}||^2 - \nu
\rho +\frac{1}{N}\sum_{i=1}^N \xi_i\right)
\] subjects constraints
\[
y_i(\mathbf{w}^T \mathbf{x}_i + b) \ge \rho - \mathbf{\xi}_i, \ \
\mathbf{\xi}_i \ge 0, \ \ \text{and} \ \ \rho > 0,
\]
where
- \(||\mathbf{w}||^2\) reflect the
margin as in C-SVM,
- \(-\nu \rho\) adjusts the margin
width \(\rho\),
- \(-\sum_{i=1}^N\xi_i/N\) penalizes
misclassifications (slack variables \(\xi_i\)).
\(\nu\) is the hyperparameter in
\(\nu\)-classification SVM that needs
to be tuned through various methods including cross-validation. It
controls the fraction of margin errors and support vectors.
- \(\nu \in (0,1]\)
- A small \(\nu\)
results in a wider margin but allows more misclassifications.
- A large \(\nu\)
results in a narrower margin but allows fewer misclassifications.
C-SVM v.s. \(\nu\)-SVM
There is a theoretical relationship between \(C\)-SVM and \(\nu\)-SVM. For a given dataset, there
exists a mapping between \(C\) and
\(\nu\) such that the solutions of
C-SVM and \(\nu\)-SVM are equivalent.
However, this mapping depends on the dataset and is not straightforward
to compute.
C-SVM and \(\nu\)-SVM can produce
the same result if:
The parameters C and \(\nu\) are
chosen such that they correspond to the same trade-off between margin
size and classification errors.
The dataset and kernel are the same.
The optimization algorithm converges to the same
solution.
In practice, this equivalence is rarely exploited because \(\nu\)-SVM provides a more intuitive way to
control the fraction of support vectors and errors, while C-SVM requires
tuning C through cross-validation or other methods.
For the convenience of comparison, we make the following table to
show the difference between the two support vector machines.
| Hyperparameter |
Uses \(C\) (cost
parameter). |
Uses \(\nu\) (nu
parameter). |
| Interpretation |
\(C\) controls the
penalty for miss-classifications. |
\(\nu\) controls the
fraction of support vectors and margin errors. |
| Range |
C can take any positive value (typically \(C>0\)). |
\(\nu\) ranges between
0 and 1 (\(0<\nu \le 1\)). |
| Focus |
Focuses on minimizing classification errors. |
Focuses on controlling the fraction of support vectors
and margin errors. |
| Margin Control |
Fixed margin |
Adaptive margin (\(\rho\)) |
| Interpretability |
Less intuitive |
More intuitive |
| Ease of Tuning |
Requires careful tuning of C to balance bias and
variance. |
Easier to interpret, as \(\nu\) directly relates to the fraction of
support vectors. |
| Use Case |
General-purpose |
Tasks requiring control over support vectors |
\(\nu\)-SVM is a powerful and
interpretable variant of SVM that provides explicit control over the
fraction of support vectors and margin errors. Its intuitive
parameterization and adaptive margin make it a valuable tool for
classification, regression, and outlier detection tasks.
SVM with R
Support Vector Machines (SVM) are a popular set of machine learning
algorithms used for classification, regression, and outlier detection.
In R, several libraries provide implementations of SVM, each with its
own features and capabilities. We will use two of the most commonly used
libraries: e1071 and kernlab. A recently
developed R library caret includes some of the R functions
in the aforementioned libraries with some additional convenient
functions for performing machine learning tasks.
- e1071: General-purpose SVM for classification and
regression tasks. It is one of the most widely used packages for SVM in
R that Supports various kernel functions (linear, polynomial, radial
basis, sigmoid) and provides tools for model tuning and
cross-validation.
svm(): Fits an SVM model for classification,
regression, or novelty detection.
tune.svm(): Performs hyperparameter tuning (e.g., cost,
gamma) using grid search.
- kernlab: Advanced SVM tasks with custom kernels or
specialized requirements. It is a comprehensive package for kernel-based
machine learning, including SVM. It offers a wide range of kernel
functions and is highly flexible.
ksvm(): Fits an SVM model with support for multiple
kernel types.
kernelMatrix(): Computes the kernel matrix for custom
kernels.
- caret: Streamlined SVM modeling with automated
tuning and evaluation. It is a meta-package for machine learning that
provides a unified interface for various models, including SVM. It uses
e1071 or kernlab under the hood and simplifies
model training and evaluation and integrates with other machine learning
workflows.
train(): Fits an SVM model with hyperparameter tuning
and cross-validation.
LS0tDQp0aXRsZTogJ1N1cHBvcnQgVmVjdG9yIE1hY2hpbmUgKFNWTSk6IENvbmNlcHRzIGFuZCBGb3JtdWxhdGlvbnMnDQphdXRob3I6ICJDaGVuZyBQZW5nIg0KZGF0ZTogIldlc3QgQ2hlc3RlciBVbml2ZXJzaXR5Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICB0aGVtZTogbHVtZW4NCiAgd29yZF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAga2VlcF9tZDogeWVzDQogIHBkZl9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiBubw0KICAgIGZpZ193aWR0aDogMw0KICAgIGZpZ19oZWlnaHQ6IDMNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHs9aHRtbH0NCg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCg0KLyogQ2FzY2FkaW5nIFN0eWxlIFNoZWV0cyAoQ1NTKSBpcyBhIHN0eWxlc2hlZXQgbGFuZ3VhZ2UgdXNlZCB0byBkZXNjcmliZSB0aGUgcHJlc2VudGF0aW9uIG9mIGEgZG9jdW1lbnQgd3JpdHRlbiBpbiBIVE1MIG9yIFhNTC4gaXQgaXMgYSBzaW1wbGUgbWVjaGFuaXNtIGZvciBhZGRpbmcgc3R5bGUgKGUuZy4sIGZvbnRzLCBjb2xvcnMsIHNwYWNpbmcpIHRvIFdlYiBkb2N1bWVudHMuICovDQoNCmgxLnRpdGxlIHsgIC8qIFRpdGxlIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiB0aGUgcmVwb3J0IHRpdGxlICovDQogIGZvbnQtc2l6ZTogMjJweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCn0NCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgYXV0aG9ycyAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsNCiAgY29sb3I6IG5hdnk7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIHRoZSBkYXRlICAqLw0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCmgxIHsgLyogSGVhZGVyIDEgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAxIHNlY3Rpb24gdGl0bGUgICovDQogICAgZm9udC1zaXplOiAyMnB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCn0NCmgyIHsgLyogSGVhZGVyIDIgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAyIHNlY3Rpb24gdGl0bGUgKi8NCiAgICBmb250LXNpemU6IDIwcHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCn0NCg0KaDMgeyAvKiBIZWFkZXIgMyAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgMyBzZWN0aW9uIHRpdGxlICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCA0IHNlY3Rpb24gdGl0bGUgICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9DQoNCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCjwvc3R5bGU+DQpgYGANCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgDQojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgidGlkeXZlcnNlIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCn0NCmlmICghcmVxdWlyZSgicGFsbWVycGVuZ3VpbnMiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGFsbWVycGVuZ3VpbnMiKQ0KbGlicmFyeShwYWxtZXJwZW5ndWlucykNCn0NCmlmICghcmVxdWlyZSgicGxvdGx5IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBsb3RseSIpDQpsaWJyYXJ5KHBsb3RseSkNCn0NCmlmICghcmVxdWlyZSgiZTEwNzEiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiZTEwNzEiKQ0KbGlicmFyeShlMTA3MSkNCn0NCmlmICghcmVxdWlyZSgibW1lbG4iKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygibW1lbG4iKQ0KbGlicmFyeShtbWVsbikNCn0NCmlmICghcmVxdWlyZSgiTUFTUyIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIikNCmxpYnJhcnkoTUFTUykNCn0NCmlmICghcmVxdWlyZSgiZ2dwbG90MiIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikNCmxpYnJhcnkoZ2dwbG90MikNCn0NCmlmICghcmVxdWlyZSgicGxvdGx5IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBsb3RseSIpDQpsaWJyYXJ5KHBsb3RseSkNCn0NCmlmICghcmVxdWlyZSgiY2FyZXQiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiY2FyZXQiKQ0KbGlicmFyeShjYXJldCkNCn0NCiMjICAgIyBGb3IgZGF0YSBwcmVwcm9jZXNzaW5nDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQQ0KICAgICAgICAgICAgICAgICAgICAgICkgIA0KYGBgDQoNClwNCg0KIyBJbnRyb2R1Y3Rpb24NCg0KU3VwcG9ydCBWZWN0b3IgTWFjaGluZXMgKFNWTSkgYXJlIGEgcG93ZXJmdWwgYW5kIHZlcnNhdGlsZSBzZXQgb2Ygc3VwZXJ2aXNlZCBsZWFybmluZyBhbGdvcml0aG1zIHdpZGVseSB1c2VkIGZvciBjbGFzc2lmaWNhdGlvbiwgcmVncmVzc2lvbiwgYW5kIG91dGxpZXIgZGV0ZWN0aW9uIHRhc2tzLiBJdCBpcyBwYXJ0aWN1bGFybHkgd2VsbC1zdWl0ZWQgZm9yIHByb2JsZW1zIGludm9sdmluZyBjb21wbGV4LCBoaWdoLWRpbWVuc2lvbmFsIGRhdGEgYW5kIGlzIHJvYnVzdCBhZ2FpbnN0IG92ZXJmaXR0aW5nLg0KDQoNCioqQmluYXJ5IENsYXNzaWZpY2F0aW9uKio6IFNWTSBpcyB3aWRlbHkgdXNlZCB0byBjbGFzc2lmeSBkYXRhIGludG8gdHdvIGRpc3RpbmN0IGNsYXNzZXMgYnkgZmluZGluZyB0aGUgYmVzdCBkZWNpc2lvbiBib3VuZGFyeSAoaHlwZXJwbGFuZSkgdGhhdCBzZXBhcmF0ZXMgdGhlIGNsYXNzZXMgd2l0aCB0aGUgbWF4aW11bSBtYXJnaW4uDQoNCioqTXVsdGktY2xhc3MgQ2xhc3NpZmljYXRpb24qKjogU1ZNIGNhbiBoYW5kbGUgbXVsdGktY2xhc3MgcHJvYmxlbXMgYnkgY29tYmluaW5nIG11bHRpcGxlIGJpbmFyeSBjbGFzc2lmaWVycyB1c2luZyB0ZWNobmlxdWVzIGxpa2Ugb25lLXZzLW9uZSBvciBvbmUtdnMtYWxsLg0KDQoqKlJlZ3Jlc3Npb24gKFNWUiAtIFN1cHBvcnQgVmVjdG9yIFJlZ3Jlc3Npb24pKio6ICBTVk0gY2FuIHByZWRpY3QgY29udGludW91cyBvdXRwdXRzIGJ5IGZpbmRpbmcgYSBoeXBlcnBsYW5lIHRoYXQgYXBwcm94aW1hdGVzIHRoZSB0YXJnZXQgdmFyaWFibGUgd2l0aGluIGEgbWFyZ2luIG9mIHRvbGVyYW5jZS4NCg0KKipPdXRsaWVyIERldGVjdGlvbioqOiBTVk0gY2FuIGRldGVjdCBhbm9tYWxpZXMgYnkgaWRlbnRpZnlpbmcgZGF0YSBwb2ludHMgdGhhdCBkZXZpYXRlIHNpZ25pZmljYW50bHkgZnJvbSB0aGUgbWFpbiBkaXN0cmlidXRpb24uDQoNClNWTSBpcyBhIGRpc3RyaWJ1dGlvbi1mcmVlIG1ldGhvZCBmb3IgYm90aCBjbGFzc2lmaWNhdGlvbiBhbmQgcmVncmVzc2lvbi4gTGluZWFyIHN1cHBvcnQgdmVjdG9yIG1hY2hpbmVzIGFyZSBjb21tb25seSB1c2VkIGluIHByYWN0aWNlLiBIb3dldmVyLCBkZXBlbmRpbmcgb24gdGhlIGNvbXBsZXhpdHkgb2YgdGhlIHByYWN0aWNhbCBwcm9ibGVtcywgbm9uLWxpbmVhciBTVk1zIGFyZSBhbHNvIGZyZXF1ZW50bHkgdXNlZC4NCg0KVGhpcyBtb2R1bGUgZm9jdXNlcyBvbiBsaW5lYXIgU1ZNIGFuZCBpdHMgYXBwbGljYXRpb25zIGluIHJlZ3Jlc3Npb24gYW5kIGNsYXNzaWZpY2F0aW9uLiBUaGUga2VybmVsIFNWTSB3aWxsIGFsc28gYmUgaW50cm9kdWNlZCB0byBoYW5kbGUgbm9ubGluZWFyIGNsYXNzaWZpY2F0aW9uIGFuZCByZWdyZXNzaW9uIHByb2JsZW1zLg0KDQoNCiMgSG93IFNWTSBXb3Jrcz8gICANCg0KVG8gaGVscCBnYWluIGFuIGludHVpdGl2ZSB1bmRlcnN0YW5kaW5nIG9mIFNWTSwgd2UgY29uc2lkZXIgdGhlIGJpbmFyeSBjbGFzc2lmaWNhdGlvbiB0YXNrIG9mIFNWVk0gaW4gdHdvLWRpbWVuc2lvbmFsIGZlYXR1cmUgc3BhY2UgdXNpbmcgYSBzdWJzZXQgb2YgdGhlIHdlbGwta25vd24gaXJpcyBkYXRhIHNldC4NCg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9DQojIGlyaXMgZGF0YQ0KaXJpczAgPC0gaXJpc1tjKDE6NTAsIDEwMToxNTApLCBjKCJTZXBhbC5MZW5ndGgiLCAiU2VwYWwuV2lkdGgiLCJTcGVjaWVzIiApXQ0KaXJpczAgPC1pcmlzMFt3aGljaChpcmlzMCRTZXBhbC5MZW5ndGg+IDUgJiBpcmlzMCRTZXBhbC5XaWR0aD4yLjUpLF0NCiMjIHN1cHBvcnQgdmVjdG9ycw0KY3ZEYXRhID0gZGF0YS5mcmFtZSh4eD1jKDUuNSw1LjQsNS42LDYuMiksIA0KICAgICAgICAgICAgICAgICAgICB5eT1jKDMuNSwzLjQsMi44LDMuNCksIA0KICAgICAgICAgICAgICAgICAgICBwdD1jKCJBIiwgIkIiLCAiQyIsICJEIikpDQojIw0Kc3ZtZ2cgPC0gZ2dwbG90KGRhdGEgPSBpcmlzMCwgYWVzKHggPSBTZXBhbC5MZW5ndGgsIHkgPSBTZXBhbC5XaWR0aCwgY29sb3IgPSBTcGVjaWVzKSkgKw0KICAgICAgICAgZ2VvbV9wb2ludChzaGFwZT0xOSwgIHNpemU9MykgKyANCiAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9Y3ZEYXRhLCBhZXMoeD14eCwgeT15eSksIHNoYXBlID0xOSwgc2l6ZT0yLCBjb2xvciA9ICJkYXJrcmVkIikgKw0KICAgICAgICAgYW5ub3RhdGUoInRleHQiLCANCiAgICAgICAgICAgICAgICAgIHggPSBjKDUuNSw1LjQsNS42LDYuMikrMC4wNCwgDQogICAgICAgICAgICAgICAgICB5ID0gYygzLjUsMy40LDIuOCwzLjQpLTAuMDQsIA0KICAgICAgICAgICAgICAgICAgbGFiZWwgPSBjKCJBIiwgIkIiLCAiQyIsICJEIiksDQogICAgICAgICAgICAgICAgICBzaXplID0gMy4zLA0KICAgICAgICAgICAgICAgICAgY29sb3IgPSAiZGFya3JlZCIpICsNCiAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhtaW5vcl9icmVha3MgPSBzZXEoNSwgOCwgMC4xKSkgKw0KICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKG1pbm9yX2JyZWFrcyA9IHNlcSgyLjUsIDQuNSwgMC4xKSkgKw0KICAgICAgICAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMSwgDQogICAgICAgICAgICAgICAgICAgICBzbG9wZSA9IDAuNCwgDQogICAgICAgICAgICAgICAgICAgICBjb2xvcj0ibGlnaHRzZWFncmVlbiIsIA0KICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGU9MSwgDQogICAgICAgICAgICAgICAgICAgICBzaXplPTAuNSkgKw0KICAgICAgICAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gLTYsIA0KICAgICAgICAgICAgICAgICAgICAgc2xvcGUgPSAxLjcsIA0KICAgICAgICAgICAgICAgICAgICAgY29sb3I9ImluZGlhbnJlZDMiLCANCiAgICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlPTEsIA0KICAgICAgICAgICAgICAgICAgICAgc2l6ZT0wLjUpICsNCiAgICAgICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IC0yLjgsIA0KICAgICAgICAgICAgICAgICAgICAgc2xvcGUgPSAxLCANCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yPSJibHVlIiwgDQogICAgICAgICAgICAgICAgICAgICBsaW5ldHlwZT0yLCANCiAgICAgICAgICAgICAgICAgICAgIHNpemU9MC43NSkgKw0KICAgICAgICAgZ2VvbV9sYWJlbCggbGFiZWw9IkwxOiB5ID0geCAtIDIuOCIsIA0KICAgICAgICAgICAgICAgICAgICAgeD03LjMsDQogICAgICAgICAgICAgICAgICAgICB5PTQuNCwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVsLnBhZGRpbmcgPSB1bml0KDAuMjUsICJsaW5lcyIpLCAjIFJlY3RhbmdsZSBzaXplIGFyb3VuZCBsYWJlbA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWwuc2l6ZSA9IDAuMTUsDQogICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibHVlIiwNCiAgICAgICAgICAgICAgICAgICAgIGZpbGw9IndoaXRlIiApICsNCiAgICAgICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IC0yLCANCiAgICAgICAgICAgICAgICAgICAgIHNsb3BlID0gMSwgDQogICAgICAgICAgICAgICAgICAgICBjb2xvcj0iYmx1ZSIsIA0KICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGU9MiwgDQogICAgICAgICAgICAgICAgICAgICBzaXplPTAuNzUpICsNCiAgICAgICAgIGdlb21fbGFiZWwoIGxhYmVsPSJMMjogeSA9IHggLSAyIiwgDQogICAgICAgICAgICAgICAgICAgICB4PTYuMSwNCiAgICAgICAgICAgICAgICAgICAgIHk9NC4xLA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWwucGFkZGluZyA9IHVuaXQoMC4yNSwgImxpbmVzIiksICMgUmVjdGFuZ2xlIHNpemUgYXJvdW5kIGxhYmVsDQogICAgICAgICAgICAgICAgICAgICBsYWJlbC5zaXplID0gMC4xNSwNCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImJsdWUiLA0KICAgICAgICAgICAgICAgICAgICAgZmlsbD0id2hpdGUiICkgKw0KICAgICAgICAgIyBtYXJnaW4NCiAgICAgICAgIGdlb21fc2VnbWVudCh4ID0gNS45LCB5ID0gMy45LCB4ZW5kID0gNi4zLCB5ZW5kID0gMy41LA0KICAgICAgICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMDIsICJucGMiKSwgZW5kcyA9ICJib3RoIiksDQogICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJkYXJrZ3JlZW4iLCBzaXplID0gMC44NSkgICsNCiAgICAgICAgICMgbGluZWFyIGRlY2lzaW9uIGJvdW5kYXJ5DQogICAgICAgICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAtMi40LCANCiAgICAgICAgICAgICAgICAgICAgIHNsb3BlID0gMSwgDQogICAgICAgICAgICAgICAgICAgICBjb2xvcj0iZGFya3JlZCIsIA0KICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGU9MSwgDQogICAgICAgICAgICAgICAgICAgICBzaXplPTAuNzUpICsNCiAgICAgICAgIGdlb21fbGFiZWwoIGxhYmVsPSJMMzogeSA9IHggLSAyLjQiLCANCiAgICAgICAgICAgICAgICAgICAgIHg9Ni42LA0KICAgICAgICAgICAgICAgICAgICAgeT00LjI1LA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWwucGFkZGluZyA9IHVuaXQoMC4yNSwgImxpbmVzIiksICMgUmVjdGFuZ2xlIHNpemUgYXJvdW5kIGxhYmVsDQogICAgICAgICAgICAgICAgICAgICBsYWJlbC5zaXplID0gMC4xNSwNCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImRhcmtyZWQiLA0KICAgICAgICAgICAgICAgICAgICAgZmlsbD0id2hpdGUiICkgKyAgDQogICAgICAgICAjIGFubm90YXRpb24NCiAgICAgICAgIGFubm90YXRlKGdlb20gPSAidGV4dCIsIHggPSA2LjA1LCB5ID0gMy44NSwgDQogICAgICAgICAgICAgICAgICBsYWJlbCA9ICJNYXJnaW4iLCANCiAgICAgICAgICAgICAgICAgIGNvbG9yID0gImRhcmtncmVlbiIsDQogICAgICAgICAgICAgICAgICBzaXplID0gMy4xLA0KICAgICAgICAgICAgICAgICAgYW5nbGUgPSAtNDIpICsNCiAgICAgICAgICMNCiAgICAgICAgIGdlb21fbGFiZWwoIGxhYmVsPSJMNDogeSA9IDAuNHggKyAxIiwgDQogICAgICAgICAgICAgICAgICAgICB4PTcuNSwNCiAgICAgICAgICAgICAgICAgICAgIHk9NCwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVsLnBhZGRpbmcgPSB1bml0KDAuMjUsICJsaW5lcyIpLCAjIFJlY3RhbmdsZSBzaXplIGFyb3VuZCBsYWJlbA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWwuc2l6ZSA9IDAuMSwNCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImxpZ2h0c2VhZ3JlZW4iLA0KICAgICAgICAgICAgICAgICAgICAgZmlsbD0id2hpdGUiICkgKw0KICAgICAgICAgIGdlb21fbGFiZWwoIGxhYmVsPSJMNTogeSA9IDEuN3ggLSA2IiwgDQogICAgICAgICAgICAgICAgICAgICB4PTYuMSwNCiAgICAgICAgICAgICAgICAgICAgIHk9NC40LA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWwucGFkZGluZyA9IHVuaXQoMC4yNSwgImxpbmVzIiksICMgUmVjdGFuZ2xlIHNpemUgYXJvdW5kIGxhYmVsDQogICAgICAgICAgICAgICAgICAgICBsYWJlbC5zaXplID0gMC4wNSwNCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImluZGlhbnJlZDMiLA0KICAgICAgICAgICAgICAgICAgICAgZmlsbD0id2hpdGUiICkgKw0KICAgICAgICAgZ2d0aXRsZSgiS2V5IFRlcm1zIGluIFNWTSIpICsgDQogICAgICAgICB0aGVtZSggYXhpcy5saW5lID0gZWxlbWVudF9saW5lKHNpemUgPSAuNSwgY29sb3IgPSAicmVkIiksDQogICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJncmF5Iiwgc2l6ZSA9ICguMikpLA0KICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2xpbmUoc2l6ZSA9ICgwLjIpLCBjb2xvciA9ICJncmF5IiksDQogICAgICAgICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgICBwbG90Lm1hcmdpbiA9IHVuaXQoYygxLDAsMSwxKSwgImNtIiksDQogICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdD0wLjUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdCA9IDUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSAic2FucyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDE2KSwNCiAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuOSwgMC40NSksDQogICAgICAgICAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemU9MC41LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5ldHlwZT0ic29saWQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSJkYXJrYmx1ZSIpLA0KICAgICAgICAgICAgICAgIGFzcGVjdC5yYXRpbz0wLjU1KQ0Kc3ZtZ2cNCiNnZ3Bsb3RseShzdm1nZykNCmBgYA0KDQoqKkZlYXR1cmUgU3BhY2UqKjogQSBmZWF0dXJlIHNwYWNlIGlzIHNwYW5uZWQgYnkgYSBzZXQgb2YgZmVhdHVyZSB2YXJpYWJsZXMgKGluZGVwZW5kZW50IHZhcmlhYmxlLCBwcmVkaWN0b3IgdmFyaWFibGUpLiBJbiB0aGUgYWJvdmUgZmlndXJlLiBUaGUgYGRlcGVuZGVudCB2YXJpYWJsZWAgKG5vdCBjb25zaWRlcmVkIGFzIGEgZmVhdHVyZSB2YXJpYWJsZSkgaXMgYFNwZWNpZXNgLiBgU2VwYWwuTGVuZ3RoYCBhbmQgYFNlcGFsLldpZHRoYCBhcmUgdGhlIHR3byBmZWF0dXJlIHZhcmlhYmxlcy4gVGhlIHR3by1kaW1lbnNpb25hbCBjb29yZGluYXRlIHN5c3RlbSBzaG93biBpbiB0aGUgYWJvdmUgZmlndXJlIGlzIGNhbGxlZCB0d28tZGltZW5zaW9uYWwgZmVhdHVyZSBzcGFjZS4gKipUaGUgZGltZW5zaW9uIG9mIGZlYXR1cmUgc3BhY2UgaXMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiAodW5jb3JyZWxhdGVkKSBmZWF0dXJlIHZhcmlhYmxlcy4qKiANCg0KKipIeXBlcnBsYW5lKio6IFRoZSAqKmh5cGVycGxhbmUqKiBpcyBhIGRlY2lzaW9uIGJvdW5kYXJ5IHRoYXQgc2VwYXJhdGVzIGNsYXNzZXMgaW4gdGhlIGZlYXR1cmUgc3BhY2UuIEluIHRoZSBhYm92ZSAyRCBmaWd1cmUsIHRoZSBgaHlwZXJwbGFuZWAgaXMgYW55ICoqc3RyYWlnaHQgbGluZSoqIHRoYXQgc2VwYXJhdGVzIHRoZSB0d28gYFNwZWNpZXNgLiBJbiBnZW5lcmFsLCB0aGUgZGltZW5zaW9uIG9mIGEgYGh5cGVycGxhbmVgIGluIGFuIG4tZGltZW5zaW9uYWwgYGZlYXR1cmUgc3BhY2VgIGlzICRuLTEkLiANCg0KDQoqKk1hcmdpbioqOiBUaGUgbWFyZ2luIGlzIHRoZSBkaXN0YW5jZSBiZXR3ZWVuIHRoZSB0d28gKipwYXJhbGxlbCoqIGh5cGVyLXBsYW5lcyB0aGF0IHNlcGFyYXRlIHRoZSB0d28gY2xhc3NlcyBvZiB0aGUgcmVzcG9uc2UgdmFyaWFibGUuIEluIHRoZSBhYm92ZSBmaWd1cmUsIHRoZSBwYXJhbGxlbCBoeXBlcnBsYW5lcyAkTDEkIGFuZCAkTDIkIGNvbXBsZXRlbHkgc2VwYXJhdGUgdGhlIHR3byBjbGFzc2VzLg0KDQoqKlN1cHBvcnQgVmVjdG9ycyoqOiBTdXBwb3J0IHZlY3RvcnMgYXJlIHRoZSBwb2ludHMgKipjbG9zZXN0KiogdG8gdGhlIGRlY2lzaW9uIGJvdW5kYXJ5LCA8Zm9udCBjb2xvciA9ICJyZWQiPioqbm90IG9uIGl0Kio8L2ZvbnQ+LiBUaGVzZSBwb2ludHMgYXJlIGxvY2F0ZWQgb24gdGhlIG1hcmdpbnMgdGhhdCBkZWZpbmUgdGhlICoqbWF4aW11bS1tYXJnaW4gaHlwZXJwbGFuZSoqLiBUaGUgZGVjaXNpb24gYm91bmRhcnkgaXRzZWxmIGlzIHBvc2l0aW9uZWQgZXF1aWRpc3RhbnQgYmV0d2VlbiB0aGVzZSBtYXJnaW5zLCBhbmQgdGhlIHN1cHBvcnQgdmVjdG9ycyBhcmUgdGhlIGRhdGEgcG9pbnRzIHRoYXQgZGV0ZXJtaW5lIHRoZSBtYXJnaW4gd2lkdGguDQoNCioqU1ZNIEFsZ29yaXRobSoqOiBNYXhpbWl6ZSB0aGUgbWFyZ2luIHdoaWxlIG1pbmltaXppbmcgbWlzY2xhc3NpZmljYXRpb24gZXJyb3JzLg0KDQoNCg0KDQoNCiMgVGhlIEtlcm5lbCBUcmljaw0KDQoqKktlcm5lbHMqKiBhcmUgYSBmdW5kYW1lbnRhbCBjb25jZXB0IGluIG1hY2hpbmUgbGVhcm5pbmcsIHBhcnRpY3VsYXJseSBpbiBhbGdvcml0aG1zIGxpa2UgKipTdXBwb3J0IFZlY3RvciBNYWNoaW5lcyAoU1ZNcykqKiwgKipLZXJuZWwgUENBKiosIGFuZCAqKkdhdXNzaWFuIFByb2Nlc3NlcyoqLiBUaGV5IGFsbG93IHVzIHRvIGltcGxpY2l0bHkgbWFwIGRhdGEgaW50byBhIGhpZ2hlci1kaW1lbnNpb25hbCBzcGFjZSwgZW5hYmxpbmcgdGhlIG1vZGVsaW5nIG9mIGNvbXBsZXgsIG5vbmxpbmVhciByZWxhdGlvbnNoaXBzIHdpdGhvdXQgZXhwbGljaXRseSBjb21wdXRpbmcgdGhlIHRyYW5zZm9ybWF0aW9uLg0KDQoNCiMjIEtlcm5lbCBGdW5jdGlvbg0KDQpBIGtlcm5lbCBpcyBhIGZ1bmN0aW9uICRLKHgseSkkIHRoYXQgY29tcHV0ZXMgdGhlIHNpbWlsYXJpdHkgYmV0d2VlbiB0d28gZGF0YSBwb2ludHMgJHgkIGFuZCAkeSQgaW4gYSBoaWdoLWRpbWVuc2lvbmFsIHNwYWNlLiBUaGUga2V5IGlkZWEgaXMgdG8gYXZvaWQgZXhwbGljaXRseSB0cmFuc2Zvcm1pbmcgdGhlIGRhdGEgaW50byB0aGF0IGhpZ2gtZGltZW5zaW9uYWwgc3BhY2UsIHdoaWNoIGNhbiBiZSBjb21wdXRhdGlvbmFsbHkgZXhwZW5zaXZlLiBJbnN0ZWFkLCBrZXJuZWxzIGNvbXB1dGUgdGhlICoqaW5uZXIgcHJvZHVjdCoqIGluIHRoYXQgc3BhY2UgZGlyZWN0bHkuIA0KDQoNCiMjIyBJbm5lciBQcm9kdWN0DQoNCkZvciB0d28gdmVjdG9ycyB1IGFuZCB2IGluIGFuIGlubmVyIHByb2R1Y3Qgc3BhY2UsIHRoZWlyIGlubmVyIHByb2R1Y3QgaXMgZGVub3RlZCBhczoNCg0KJCQNClxsYW5nbGUgXG1hdGhiZnt1fSxcbWF0aGJme3Z9XHJhbmdsZQ0KJCQNCg0KVGhlIGlubmVyIHByb2R1Y3QgbXVzdCBzYXRpc2Z5IHRoZSBmb2xsb3dpbmcgcHJvcGVydGllczoNCg0KKiBMaW5lYXJpdHk6ICRcbGFuZ2xlIGFcbWF0aGJme3V9ICsgYlxtYXRoYmZ7dn0sXG1hdGhiZnt3fVxyYW5nbGU9YVxsYW5nbGUgXG1hdGhiZnt1fSxcbWF0aGJme3d9IFxyYW5nbGUgKyBiXGxhbmdsZSBcbWF0aGJme3Z9LCBcbWF0aGJme3d9XHJhbmdsZSQNCg0KKiBDb25qdWdhdGUgU3ltbWV0cnk6ICRcbGFuZ2xlIFxtYXRoYmZ7dX0sXG1hdGhiZnt2fVxyYW5nbGU9XG92ZXJsaW5le1xsYW5nbGUgXG1hdGhiZnt2fSxcbWF0aGJme3V9XHJhbmdsZX0kIA0KDQoqIFBvc2l0aXZpdHk6ICRcbGFuZ2xlIFxtYXRoYmZ7dX0sXG1hdGhiZnt1fVxyYW5nbGUgXGdlIDAkLCBhbmQgJFxsYW5nbGUgXG1hdGhiZnt1fSxcbWF0aGJme3Z9XHJhbmdsZT0wJCBpZiBhbmQgb25seSBpZiAkXG1hdGhiZnt1fT1cbWF0aGJmezB9LiQNCg0KDQpBcyBhbiBleGFtcGxlLCAqKmRvdCBwcm9kdWN0KiogaW4gJFxtYXRoYmJ7Un1ebiQgaXMgYW4gaW5uZXIgcHJvZHVjdDoNCg0KJCQNClxtYXRoYmZ7dX0gPSAodV8xLCB1XzIsIFxjZG90cywgdV9rKSwgXCAgXCAgXG1hdGhiZnt2fSA9ICh2XzEsIHZfMiwgXGNkb3RzLCB2X2spLg0KJCQNClRoZSBpbm5lciBwcm9kdWN0IChkb3QgcHJvZHVjdCkgb2YgJG1hdGhiZnt1fSQgYW5kICRcbWF0aGJme3Z9JCBpcw0KDQokJA0KeiA9IFxsYW5nbGUgXG1hdGhiZnt1fSwgXG1hdGhiZnt2fSBccmFuZ2xlID0gdV8xdl8xICsgdV8ydl8yICsgXGNkb3RzICsgdV9rdl9rLg0KJCQNCk51bWVyaWNhbCBleGFtcGxlLCAkXG1hdGhiZnt1fSA9ICgxLDIpJCBhbmQgJFxtYXRoYmZ7dn0gPSAoNCwtNSkkLCB0aGVuIA0KDQokJA0KeiA9IFxsYW5nbGUgXG1hdGhiZnt1fSwgXG1hdGhiZnt2fSBccmFuZ2xlID0gMVx0aW1lcyA0ICsgMlx0aW1lcygtNSkgID0gNC0xMCAgPSAtNi4NCiQkDQoNCiMjIyBTVk0gRGVmYXVsdCBSQkYgS2VybmVsIDxmb250IGNvbG9yID0gInJlZCI+PGI+W09wdGlvbmFsXTwvYj48L2ZvbnQ+DQoNCkFtb25nIHRoZSBtYW55IGF2YWlsYWJsZSBrZXJuZWxzLCB0aGUgUkJGIEtlcm5lbCAoUmFkaWFsIEJhc2lzIEZ1bmN0aW9uKSwgYWxzbyBrbm93biBhcyB0aGUgR2F1c3NpYW4ga2VybmVsLCBpcyB0aGUgbW9zdCBjb21tb25seSB1c2VkIGluIHByYWN0aWNlLiBUaGlzIGtlcm5lbCBpcyBoaWdobHkgcG9wdWxhciBiZWNhdXNlIGl0IGNhbiBlZmZlY3RpdmVseSBoYW5kbGUgYm90aCBsaW5lYXIgYW5kIG5vbi1saW5lYXIgZGVjaXNpb24gYm91bmRhcmllcyBpbiB0aGUgb3JpZ2luYWwgaW5wdXQgc3BhY2UuIFRoZSBkZWNpc2lvbiBmdW5jdGlvbiAkZih4KSQsIHdoZW4gZXZhbHVhdGVkIG92ZXIgYSBncmlkIG9mIHBvaW50cyBpbiB0aGUgaW5wdXQgc3BhY2UsIGlzIG1hcHBlZCBpbnRvIGEgaGlnaGVyLWRpbWVuc2lvbmFsIGZlYXR1cmUgc3BhY2UuIFRoaXMgbWFwcGluZyBjcmVhdGVzIGEgbGlmdGVkIHN1cmZhY2UsIHdoaWNoIHJlcHJlc2VudHMgdGhlIGRlY2lzaW9uIGJvdW5kYXJ5IGluIHRoZSB0cmFuc2Zvcm1lZCBzcGFjZS4NCg0KDQpIZXJlLCB3ZSBkZXJpdmUgdGhlIG1hdGhlbWF0aWNhbCBleHByZXNzaW9uIGZvciB0aGUgUkJGLWxpZnRlZCBzdXJmYWNlIGFuZCBleHBsYWluIGl0cyBjb21wb25lbnRzLg0KDQoqKjEuIFJCRiBLZXJuZWwgRnVuY3Rpb24qKg0KDQpUaGUgUkJGIGtlcm5lbCBpcyBkZWZpbmVkIGFzDQoNCiQkDQpLKFxtYXRoYmZ7eH1faSwgXG1hdGhiZnt4fV9qKSA9IFxleHBcbGVmdCggLVxnYW1tYSB8fFxtYXRoYmZ7eH1faSAtIFxtYXRoYmZ7eH1faiB8fF4yXHJpZ2h0KQ0KJCQNCg0Kd2hlcmUgDQoNCiogJFxtYXRoYmZ7eH1faSwgXG1hdGhiZnt4fV9qJCAgYXJlIGlucHV0IGZlYXR1cmUgdmVjdG9ycy4NCiogJFxnYW1tYSQgaXMgdGhlIGh5cGVycGFyYW1ldGVyIGNvbnRyb2xsaW5nIHRoZSBpbmZsdWVuY2Ugb2YgZWFjaCB0cmFpbmluZyBzYW1wbGUuDQoqICR8fFxtYXRoYmZ7eH1faSAtIFxtYXRoYmZ7eH1faiB8fF4yJCBpcyB0aGUgc3F1YXJlZCBFdWNsaWRlYW4gZGlzdGFuY2UgYmV0d2VlbiAkXG1hdGhiZnt4fV9pJCBhbmQgJFxtYXRoYmZ7eH1faiQuIA0KDQoNCioqMi4gU1ZNIERlY2lzaW9uIEJvdW5kYXJ5KioNCg0KVGhlIGRlY2lzaW9uIGZ1bmN0aW9uIGZvciBhbiBTVk0gd2l0aCB0aGUgUkJGIGtlcm5lbCBpczoNCg0KJCQNCmYoXG1hdGhiZnt4fSkgPSBcc3VtX3tpPTF9XktcYWxwaGFfaSB5X2kgSyhcbWF0aGJme3h9X2ksIFxtYXRoYmZ7eH0pICsgYg0KJCQNCg0Kd2hlcmUNCg0KKiAkTiQgaXMgdGhlIG51bWJlciBvZiBzdXBwb3J0IHZlY3RvcnMgKGkuZS4sIHRoZSBwb2ludHMgb24gdGhlIGRlY2lzaW9uIGJvdW5kYXJ5KS4NCiogJFxhbHBoYV9pJCBhcmUgdGhlICoqTGFncmFuZ2UgbXVsdGlwbGllcnMqKiAoPGZvbnQgY29sb3IgPSAicmVkIj5ub24temVybyBvbmx5IGZvciBzdXBwb3J0IHZlY3RvcnM8L2ZvbnQ+KS4NCiogJHlfaSQgYXJlIGNsYXNzIGxhYmVscyAoJCsxJCwgb3IgJC0xJCkuDQoqICRiJCBpcyB0aGUgYmlhcyB0ZXJtLg0KDQpTdWJzdGl0dXRpbmcgdGhlIFJCRiBrZXJuZWwgaW50byB0aGUgZGVjaXNpb24gZnVuY3Rpb24sIHdlIGdldA0KDQokJA0KZihcbWF0aGJme3h9KSA9IFxzdW1fe2k9MX1eS1xhbHBoYV9pIHlfaSBcZXhwXGxlZnQoLVxnYW1tYSB8fFxtYXRoYmZ7eH1faSAtIFxtYXRoYmZ7eH18fF4yXHJpZ2h0KSArIGINCiQkDQoNCioqMy4gUkJGIExpZnRlZCBTdXJmYWNlKioNCg0KVGhlIFJCRiBsaWZ0ZWQgc3VyZmFjZSBpcyB0aGUgZXZhbHVhdGlvbiBvZiB0aGUgZGVjaXNpb24gZnVuY3Rpb24gJGYoeCkkIG92ZXIgYSBncmlkIG9mIHBvaW50cyBpbiB0aGUgaW5wdXQgc3BhY2UuIEZvciBhIDJEIGlucHV0IHNwYWNlICgkeD1beF8xLHhfMl0kKSwgdGhlIGxpZnRlZCBzdXJmYWNlIGlzIGEgM0Qgc3VyZmFjZSB3aGVyZToNCg0KKiBUaGUgJHhfMSQgYW5kICR4XzIkIGF4ZXMgcmVwcmVzZW50IHRoZSBpbnB1dCBmZWF0dXJlIHNwYWNlLg0KKiBUaGUgei1heGlzIHJlcHJlc2VudHMgdGhlIHZhbHVlIG9mIHRoZSBkZWNpc2lvbiBmdW5jdGlvbiAkZih4KSQuDQoNClRoZSBtYXRoZW1hdGljYWwgZXhwcmVzc2lvbiBvZiB0aGUgbGlmdGVkIHN1cmZhY2UgaXMNCg0KJCQNCnogPSBmKHhfMSwgeF8yKSA9IFxzdW1fe2k9MX1eTiBcYWxwaGFfaSB5X2kgXGV4cFxsZWZ0KC1cZ2FtbWEgWyh4XzEteF97aTF9KV4yKyh4XzIteF97aTJ9KV4yXVxyaWdodCkgKyBiLg0KJCQNCg0Kd2hlcmUNCg0KKiAkKHhfe2kxfSwgeF97aTJ9KSQgYXJlIHRoZSBjb29yZGluYXRlcyBvZiB0aGUgaS10aCBzdXBwb3J0IHZlY3Rvci4NCiogJCh4X3sxfSwgeF97Mn0pJCBhcmUgdGhlIGNvb3JkaW5hdGVzIG9mIGEgcG9pbnQgaW4gdGhlIGlucHV0IHNwYWNlLg0KKiAkXGFscGhhX2kkIGFyZSB0aGUgKipMYWdyYW5nZSBtdWx0aXBsaWVycyoqICg8Zm9udCBjb2xvciA9ICJyZWQiPm5vbi16ZXJvIG9ubHkgZm9yIHN1cHBvcnQgdmVjdG9yczwvZm9udD4pLg0KKiAkeV9pJCBhcmUgY2xhc3MgbGFiZWxzICgkKzEkLCBvciAkLTEkKS4NCiogJGIkIGlzIHRoZSBiaWFzIHRlcm0uDQoNCg0KKio0LiBWaXN1YWxpemluZyB0aGUgTGlmdGVkIFN1cmZhY2UqKg0KDQpUbyB2aXN1YWxpemUgdGhlIGxpZnRlZCBzdXJmYWNlDQoNCiogQ3JlYXRlIGEgZ3JpZCBvZiBwb2ludHMgJCh4XzEsIHhfMikkIGluIHRoZSBpbnB1dCBzcGFjZS4NCiogRXZhbHVhdGUgJGYoeF8xLCB4XzIpJCBhdCBlYWNoIGdyaWQgcG9pbnQuDQoqIFBsb3QgdGhlIHN1cmZhY2UgJHo9Zih4XzEsIHhfMikkIGluIDNELg0KDQpHcmFwaGljYWwgcmVwcmVzZW50YXRpb24gb2YgUkJGIHdpdGggMkQgaW5wdXQgZmVhdHVyZSBzcGFjZS4NCg0KYGBge3IgZWNobyA9IEZBTFNFLCBmaWcuYWxpZ249J2NlbnRlcicsIG91dC53aWR0aD0iOTAlIn0NCmluY2x1ZGVfZ3JhcGhpY3MoImltZy9SQkYtS2VybmVsLnBuZyIpDQpgYGANCg0KDQojIyMgT3RoZXIgQ29tbW9uIEtlcm5lbCBGdW5jdGlvbnMNCg0KKiAqKkxpbmVhciBLZXJuZWwqKjogVGhpcyBpcyB0aGUgc2ltcGxlc3Qga2VybmVsLCB3aGljaCBjb21wdXRlcyB0aGUgZG90IHByb2R1Y3Qgb2YgdGhlIGlucHV0IHZlY3RvcnMuIEl0IGlzIHVzZWQgd2hlbiB0aGUgZGF0YSBpcyBhbHJlYWR5IGxpbmVhcmx5IHNlcGFyYWJsZS4gVGhlIGV4cGxpY2l0IGZvcm0gaXMgZ2l2ZW4gYnkNCg0KJCQNCksoeCx5KT1cbWF0aGJme3h9XlRcbWF0aGJme3l9DQokJA0KDQoqICoqUG9seW5vbWlhbCBLZXJuZWwqKjogVGhpcyBrZXJuZWwgY29tcHV0ZXMgdGhlIHNpbWlsYXJpdHkgYmV0d2VlbiB2ZWN0b3JzIHVzaW5nIGEgcG9seW5vbWlhbCBmdW5jdGlvbi4gVGhlIGRlZ3JlZSAkZCQgYW5kIHRoZSBjb25zdGFudCAgJGMkIGFyZSBwYXJhbWV0ZXJzIHRoYXQgY29udHJvbCB0aGUgc2hhcGUgb2YgdGhlIGRlY2lzaW9uIGJvdW5kYXJ5LiBJdHMgZnVuY3Rpb24gaXMgZ2l2ZW4gYnkNCg0KJCQNCksoeCx5KT0oXG1hdGhiZnt4fV5UXG1hdGhiZnt5fStjKV5kDQokJA0KDQoqICoqUmFkaWFsIEJhc2lzIEZ1bmN0aW9uIChSQkYpIEtlcm5lbCAoR2F1c3NpYW4gS2VybmVsKSoqOiBUaGlzIGtlcm5lbCBpcyBvbmUgb2YgdGhlIG1vc3QgcG9wdWxhciBhbmQgaXMgdXNlZCB3aGVuIHRoZSBkZWNpc2lvbiBib3VuZGFyeSBpcyBleHBlY3RlZCB0byBiZSBoaWdobHkgbm9ubGluZWFyLiBUaGUgcGFyYW1ldGVyICRcc2lnbWEkIGNvbnRyb2xzIHRoZSB3aWR0aCBvZiB0aGUgR2F1c3NpYW4uDQoNCiQkDQpLKHgseSk9XGV4cCBcbGVmdCgtXGZyYWN7fHxcbWF0aGJme3h9LVxtYXRoYmZ7eX18fF4yfXsyXHNpZ21hXjJ9XHJpZ2h0KSANCiQkDQoNCg0KKiAqKlNpZ21vaWQgS2VybmVsKio6IFRoaXMga2VybmVsIGlzIHNpbWlsYXIgdG8gdGhlIGFjdGl2YXRpb24gZnVuY3Rpb24gdXNlZCBpbiBuZXVyYWwgbmV0d29ya3MgYW5kIGNhbiBiZSB1c2VkIGluIFNWTXMgdG8gY3JlYXRlIGEgZGVjaXNpb24gYm91bmRhcnkgdGhhdCByZXNlbWJsZXMgYSBuZXVyYWwgbmV0d29yay4NCg0KJCQNCksoeCx5KT1cdGV4dHt0YW5ofShcYWxwaGEgXG1hdGhiZnt4fV5UXG1hdGhiZnt5fStjKQ0KJCQNCg0KDQojIyBBcHBsaWNhdGlvbnMgb2YgS2VybmVsIEZ1bmN0aW9ucw0KDQpLZXJuZWwgZnVuY3Rpb25zIGhhdmUgYmVlbiB1c2VkIGluIHZhcmlvdXMgYXBwbGljYXRpb25zIGluIG1hY2hpbmUgbGVhcm5pbmcgYWxnb3JpdGhtcyBzdWNoIGFzIFNWTXMgYW5kIFBDQXMuIEhlcmUgYXJlIGEgZmV3IGJlbmVmaXRzOiANCg0KKiAqKkhhbmRsaW5nIE5vbmxpbmVhcml0eSoqOiAgS2VybmVscyBhbGxvdyBhbGdvcml0aG1zIHRvIGxlYXJuIGNvbXBsZXgsIG5vbmxpbmVhciByZWxhdGlvbnNoaXBzIGluIHRoZSBkYXRhIGJ5ICoqaW1wbGljaXRseSoqIG1hcHBpbmcgdGhlIGRhdGEgdG8gYSBoaWdoZXItZGltZW5zaW9uYWwgc3BhY2Ugd2hlcmUgbGluZWFyIHNlcGFyYXRpb24gaXMgcG9zc2libGUuIFdlIHdpbGwgdXNlIGFuIGV4YW1wbGUgdG8gaWxsdXN0cmF0ZSB0aGVzZSBhcHBsaWNhdGlvbnMgaW4gdGhlIG5leHQgc3Vic2VjdGlvbi4NCg0KKiAqKkNvbXB1dGF0aW9uYWwgRWZmaWNpZW5jeSoqOiBLZXJuZWxzIGVuYWJsZSB0aGUgY29tcHV0YXRpb24gb2YgaW5uZXIgcHJvZHVjdHMgaW4gaGlnaC1kaW1lbnNpb25hbCBzcGFjZXMgd2l0aG91dCBleHBsaWNpdGx5IGNvbXB1dGluZyB0aGUgY29vcmRpbmF0ZXMgaW4gdGhhdCBzcGFjZSwgd2hpY2ggY2FuIGJlIGNvbXB1dGF0aW9uYWxseSBleHBlbnNpdmUuDQoNCiogKipGbGV4aWJpbGl0eSoqOiBEaWZmZXJlbnQga2VybmVscyBjYW4gYmUgY2hvc2VuIGJhc2VkIG9uIHRoZSBzcGVjaWZpYyBwcm9ibGVtIGFuZCB0aGUgbmF0dXJlIG9mIHRoZSBkYXRhLCBhbGxvd2luZyBmb3IgYSBoaWdoIGRlZ3JlZSBvZiBjdXN0b21pemF0aW9uLg0KDQoNCg0KDQoNCg0KIyMgQSBTaW11bGF0ZWQgRGVtb25zdHJhdGl2ZSBFeGFtcGxlDQoNCldlIHVzZSBhbiBleGFtcGxlIHRvIGlsbHVzdHJhdGUgaG93IHRvIHV0aWxpemUgYSBrZXJuZWwgZnVuY3Rpb24gdG8gbGlmdCBhIGxvdy1kaW1lbnNpb25hbCBwcm9ibGVtIGludG8gYSBoaWdoLWRpbWVuc2lvbmFsIHNwYWNlIGluIFIuIFdlJ2xsIHVzZSBhIHNpbXBsZSBleGFtcGxlIG9mIGNsYXNzaWZ5aW5nIG5vbi1saW5lYXJseSBzZXBhcmFibGUgZGF0YSB1c2luZyBhIFN1cHBvcnQgVmVjdG9yIE1hY2hpbmUgKFNWTSkgd2l0aCBhIGtlcm5lbCBmdW5jdGlvbi4NCg0KIyMjIFZpc3VhbCBJbGx1c3RyYXRpb24NCg0KU3VwcG9zZSB3ZSBoYXZlIGEgZGF0YXNldCBpbiAyRCBzcGFjZSB0aGF0IGlzIG5vdCBsaW5lYXJseSBzZXBhcmFibGUuIFdlIGNhbiB1c2UgYSBrZXJuZWwgZnVuY3Rpb24gdG8gbWFwIHRoaXMgZGF0YSBpbnRvIGEgaGlnaGVyLWRpbWVuc2lvbmFsIHNwYWNlIHdoZXJlIGl0IGJlY29tZXMgbGluZWFybHkgc2VwYXJhYmxlLg0KDQoqKkdlbmVyYXRlIE5vbi1saW5lYXJseSBTZXBhcmFibGUgRGF0YSoqDQoNCldlIGZpcnN0IGdlbmVyYXRlIDMwMCBub24tbGluZWFybHkgc2VwYXJhYmxlIGRhdGEgaW4gMkQgc3BhY2UgdXNpbmcgYSBiaXZhcmlhdGUgbm9ybWFsIGRpc3RyaWJ1dGlvbiB3aXRoIG1lYW4gdmVjdG9yICRcbWF0aGJme1xtdX09YygxMCwgMjApJCBhbmQgdmFyaWFuY2UtY292YXJpYW5jZSBtYXRyaXggDQoNCiQkDQpcbWF0aGJme1xTaWdtYX0gPSBcYmVnaW57Ym1hdHJpeH0gDQogICAgICAgICAgICAgICAgICAgICAgICA1ICAmICAzIFxcDQogICAgICAgICAgICAgICAgICAgICAgICAzICAmICA2DQogICAgICAgICAgICAgICAgICBcZW5ke2JtYXRyaXh9DQogICAgICAgICAgICAgICAgPSBcYmVnaW57Ym1hdHJpeH0gDQogICAgICAgICAgICAgICAgICAgICAgICAoXHNxcnR7NX0pXjIgICYgIFxyaG8gXHNxcnR7NX1cc3FydHs2fSBcXA0KICAgICAgICAgICAgICAgICAgICAgICAgXHJobyBcc3FydHs1fVxzcXJ0ezZ9ICAmICAoXHNxcnR7Nn0pXjINCiAgICAgICAgICAgICAgICAgIFxlbmR7Ym1hdHJpeH0sDQokJA0KDQp3aGVyZSAkXHJobyA9IFxzcXJ0ezAuM30kLiBUaGUgY29ycmVzcG9uZGluZyBkZW5zaXR5IHN1cmZhY2UgaXMgZ2l2ZW4gYmVsb3cuDQoNCg0KDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NX0NCiNsaWJyYXJ5KE1BU1MpDQpzZXQuc2VlZCgxMjMpDQojIyMNCmJ2bkRhdGEgPC0gbXZybm9ybSgNCiAgbiA9IDMwMCwgICAgICAgICAgICAgICAgICAgICAgIyBzYW1wbGUgc2l6ZQ0KICBtdSA9IGMoMTAsIDIwKSwgICAgICAgICAgICAgICAjIGxvY2FsIG1lYW4gdmVjdG9yDQogIFNpZ21hID0gbWF0cml4KGMoNSwgMywgMywgNiksIG5jb2wgPSAyKSAgICAgICMgbG9jYWwgY292YXJpYXRlIG1hdHJpeA0KICApDQojIyMjIw0KY29scyA8LSBoY2wuY29sb3JzKDEwLCAidmlyaWRpcyIpDQojIyMjIw0KeDEwIDwtIGJ2bkRhdGFbLDFdDQp4MjAgPC0gYnZuRGF0YVssMl0NCiMjIw0KbXUgPC0gYygxMCwgMjApICAgICAgICAgICAgICAgICMgZ2xvYmFsIG1lYW4gdmVjdG9yDQpzaWdtYSA8LSBtYXRyaXgoYyg1LCAzLCAzLCA2KSwgbmNvbCA9IDIpICAgICAgIyBnbG9iYWwgY292YXJpYXRlIG1hdHJpeCAgIA0KZmYgPC0gZnVuY3Rpb24oeDEsIHgyKSBkbW5vcm0oY2JpbmQoeDEsIHgyKSwgbXUsIHNpZ21hKSAgICMgRGVuc2l0eSBmdW5jdGlvbg0KZmYwIDwtIGZ1bmN0aW9uKHgxLCB4MikgezAuMDI1ICsgMCp4MSArIDAqeDJ9ICAgIyBEZW5zaXR5IGZ1bmN0aW9uDQojIyMNCiMjIyBwbG90IHRoZSBwb2ludHMgaW4gdGhlIDJEIGZlYXR1cmUgc3BhY2UNCnkgPC0gaWZlbHNlKGZmKHgxMCx4MjApID4gMC4wMjUsIDEsIDApICAgICAjIGRlZmluZSB0aGUgbGFiZWwgb2YgdGhlIDJEIHBvaW50cw0KZGF0YSA8LSBkYXRhLmZyYW1lKHgxID0geDEwLCB4MiA9IHgyMCwgeSA9IGFzLmZhY3Rvcih5KSkgICMgeSBsYWJlbA0KZGF0YTAgPC0gZGF0YVtkYXRhJHkgPT0gMCwgXSAgICMgZGF0YSB3aXRoIGxhYmVsIDANCmRhdGExIDwtZGF0YVtkYXRhJHkgPT0gMSwgXSAgICAjIGRhdGEgd2l0aCBsYWJlbCAxDQojIyBQcmVwYXJpbmcgcGxvdHMgb2YgZGF0YSBwb2ludHMgd2l0aCBsYWJlbCAwIGFuZCBsYWJlbCAxIHNlcGFyYXRlbHkNCngxLjAgPC0gZGF0YTAkeDEgICANCngyLjAgPC0gZGF0YTAkeDIgICANCngxLjEgPC0gZGF0YTEkeDENCngyLjEgPC0gZGF0YTEkeDINCiMjIyBwbG90IHRoZSBiaXZhcmlhdGUgc3VyZmFjZQ0KIyBDcmVhdGUgYSBncmlkIG9mIHBvaW50cyBjb3ZlcmluZyB0aGUgZmVhdHVyZSBzcGFjZQ0KZ3JpZF9yZXNvbHV0aW9uIDwtIDAuMSAgICAgICAgICAjIGdyaWQgc2l6ZQ0KeDFfcmFuZ2UgPC0gc2VxKG1pbihkYXRhJHgxKSwgbWF4KGRhdGEkeDEpLCBieSA9IGdyaWRfcmVzb2x1dGlvbikNCngyX3JhbmdlIDwtIHNlcShtaW4oZGF0YSR4MiksIG1heChkYXRhJHgyKSwgYnkgPSBncmlkX3Jlc29sdXRpb24pDQojIENvbnZlcnQgdG8gYSBtYXRyaXggZm9yIHBsb3RseSBzdXJmYWNlDQp6X21hdHJpeCA8LSBvdXRlcih4MV9yYW5nZSx4Ml9yYW5nZSwgZmYpICAgIyBoZWlnaHQgb2YgZ3JpZCBwb2ludCBvbiB0aGUgc3VyZmFjZQ0KejAgPC0gb3V0ZXIoeDFfcmFuZ2UsIHgyX3JhbmdlLCBmZjApICAgICAgICMgaW50ZXJzZWN0aW5nIHBsYW5lIGZvciBvYnRhaW5pbmcgY3VydmUgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBkZWNpc2lvbiBib3VuZGFyeQ0KIyAzRCBTdXJmYWNlIFBsb3QNCnBsb3RfbHkoeCA9IHgxX3JhbmdlLCANCiAgICAgICAgeSA9IHgyX3JhbmdlLCANCiAgICAgICAgeiA9IH56X21hdHJpeCwgDQogICAgICAgIHR5cGUgPSAic3VyZmFjZSIsDQogICAgICAgIGNvbnRvdXJzID0gbGlzdCggeiA9IGxpc3Qoc2hvdyA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsICAgICAgICMgc2V0IGNvbnRvdXIgY29sb3INCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGggPSAyLCAgICAgICAgICAgICAjIHNldCBjb250b3VyIHRoaWNrbmVzcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gbWluKHpfbWF0cml4ICksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZCA9IG1heCh6X21hdHJpeCApLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMC4wMTI1KSkpICAgJT4lDQogICAgICAgbGF5b3V0KHRpdGxlID0gIkJpdmFyaWF0ZSBTY2F0dGVyIFBsb3QiLA0KICAgICAgICAgICAgICBzY2VuZSA9IGxpc3QoeGF4aXMgPSBsaXN0KHRpdGxlID0gIngxIiksDQogICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJ4MiIpLA0KICAgICAgICAgICAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSAiRGVuc2l0eSIpKSwNCiAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFDQogICAgICAgICApICU+JSBoaWRlX2NvbG9yYmFyKCkgDQpgYGANCg0KDQpUaGUgMkQgc2NhdHRlciBwbG90IHdpdGggcG9pbnRzIGNvbG9yZWQgYWNjb3JkaW5nIHRvIHRoZSBsYWJlbHMgaXMgZ2l2ZW4gYmVsb3cuIA0KDQpgYGB7ciAgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01fQ0KIyMjDQpwbG90KGRhdGEkeDEsIGRhdGEkeDIsIGNvbCA9IGlmZWxzZShkYXRhJHkgPT0gMSwgY29sc1sxMF0sIGNvbHNbMV0pLCBwY2ggPSAxOSwgbWFpbiA9ICJPcmlnaW5hbCBEYXRhIikNCmBgYA0KDQpUaGUgeWVsbG93IHBvaW50cyBpbiB0aGUgbWlkZGxlIGNhbm5vdCBiZSBzZXBhcmF0ZWQgYnkgYSBzdHJhaWdodCBsaW5lIGluIHRoZSBvcmlnaW5hbCB0d28tZGltZW5zaW9uYWwgZmVhdHVyZSBzcGFjZS4gSG93ZXZlciwgYnkgcHJvamVjdGluZyB0aGUgZGF0YSBpbnRvIGEgdGhyZWUtZGltZW5zaW9uYWwgc3BhY2UsIHRoZXkgY2FuIGJlIHNlcGFyYXRlZCB1c2luZyBhIHR3by1kaW1lbnNpb25hbCBwbGFuZSwgZm9ybWluZyBhIGxpbmVhciBkZWNpc2lvbiBib3VuZGFyeSwgYXMgaWxsdXN0cmF0ZWQgaW4gdGhlIGZvbGxvd2luZyBmaWd1cmUuDQoNCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01fQ0KI2xpYnJhcnkoTUFTUykNCiNzZXQuc2VlZCgxMjMpDQojIyMjIyMjDQojIyBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIHRoaXJkIGNvb3JkaW5hdGVzIG9mIHRoZSBiaXZhcmlhdGUgZGVuc2l0eSBzdXJmYWNlDQpmZiA8LSBmdW5jdGlvbih4MSwgeDIpIGRtbm9ybShjYmluZCh4MSwgeDIpLCBtdSwgc2lnbWEpICMgRGVuc2l0eSBmdW5jdGlvbg0KIyMjIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgdGhpcmQgY29vcmRpbmF0ZXMgb2YgdGhlIGludGVyc2VjdGluZyBwbGFuZQ0KZmYwIDwtIGZ1bmN0aW9uKHgxLCB4MikgezAuMDI1ICsgMCp4MSArIDAqeDJ9ICAgIyBEZW5zaXR5IGZ1bmN0aW9uDQojIyMjIyMjDQojIyMgcGxvdCB0aGUgcG9pbnRzIGluIHRoZSAyRCBmZWF0dXJlIHNwYWNlDQp5IDwtIGlmZWxzZShmZih4MTAseDIwKSA+IDAuMDI1LCAxLCAwKSAgICAgIyBkZWZpbmUgdGhlIGxhYmVsIG9mIHRoZSAyRCBwb2ludHMNCiMjIyB3b3JraW5nIGRhdGEgc2V0DQpibi5kYXRhIDwtIGRhdGEuZnJhbWUoeDEgPSB4MTAsIHgyID0geDIwLCB5ID0gYXMuZmFjdG9yKHkpKSAgICMgeSBpcyByZXNwb25zZSBsYWJlbA0KIyMjIHBvaW50cyB3aXRoIGxhYmVsIHkgPSAwDQpibi5kYXRhMCA8LSBibi5kYXRhW2JuLmRhdGEkeSA9PSAwLCBdDQpibi54MS4wIDwtIGJuLmRhdGEwJHgxIA0KYm4ueDIuMCA8LSBibi5kYXRhMCR4Mg0KIyMjIHBvaW50cyB3aXRoIGxhYmVsIHkgPSAxDQpibi5kYXRhMSA8LWJuLmRhdGFbYm4uZGF0YSR5ID09IDEsIF0NCmJuLngxLjEgPC0gYm4uZGF0YTEkeDENCmJuLngyLjEgPC0gYm4uZGF0YTEkeDINCiMjIyBwbG90IHRoZSBiaXZhcmlhdGUgc3VyZmFjZQ0KIyBDcmVhdGUgYSBncmlkIG9mIHBvaW50cyBjb3ZlcmluZyB0aGUgZmVhdHVyZSBzcGFjZQ0KZ3JpZF9yZXNvbHV0aW9uIDwtIDAuMSAgICAgICAgICAjIGdyaWQgc2l6ZQ0KeDFfcmFuZ2UgPC0gc2VxKG1pbihibi5kYXRhJHgxKSwgbWF4KGJuLmRhdGEkeDEpLCBieSA9IGdyaWRfcmVzb2x1dGlvbikNCngyX3JhbmdlIDwtIHNlcShtaW4oYm4uZGF0YSR4MiksIG1heChibi5kYXRhJHgyKSwgYnkgPSBncmlkX3Jlc29sdXRpb24pDQojIENvbnZlcnQgdG8gbWF0cml4IGZvciBwbG90bHkgc3VyZmFjZQ0KIyMgdGhpcmQgY29vcmRpbmF0ZXMgb2YgdGhlIGJpdmFyaWF0ZSBub3JtYWwgZGVuc2l0eSBzdXJmYWNlDQp6X21hdHJpeCA8LSBvdXRlcih4MV9yYW5nZSx4Ml9yYW5nZSwgZmYpICAgIyBoZWlnaHQgb2YgZ3JpZCBwb2ludCBvbiB0aGUgc3VyZmFjZQ0KejAgPC0gb3V0ZXIoeDFfcmFuZ2UsIHgyX3JhbmdlLCBmZjApICAgICAgICMgaW50ZXJzZWN0aW5nIHBsYW5lIGZvciBvYnRhaW5pbmcgY3VydmUgDQojIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGRlY2lzaW9uIGJvdW5kYXJ5DQojIyAzRCBTdXJmYWNlIFBsb3QNCnBsb3RfbHkoKSAgICAlPiUNCiAgICAgICAgICMgYWRkaW5nIGludGVyc2VjdGluZyBwbGFuZQ0KICAgICAgICAgYWRkX3RyYWNlKHggPSAgeDFfcmFuZ2UsICAgIA0KICAgICAgICAgICAgICAgICAgIHkgPSAgeDJfcmFuZ2UsIA0KICAgICAgICAgICAgICAgICAgIHogPSAgejAsDQogICAgICAgICAgICAgICAgICAgY29sb3JzID0gInNreWJsdWUiLA0KICAgICAgICAgICAgICAgICAgIHR5cGU9InN1cmZhY2UiLA0KICAgICAgICAgICAgICAgICAgIG9wYWNpdHkgPSAwLjUpICAgJT4lDQogICAgICAgICAjIGFkZGluZyBwb2ludHMgd2l0aCBsYWJlbCB5ID0gMA0KICAgICAgICAgYWRkX3RyYWNlKHggPSBibi54MS4wLCAgICANCiAgICAgICAgICAgICAgICAgICB5ID0gYm4ueDIuMCwgDQogICAgICAgICAgICAgICAgICAgeiA9IGZmKGJuLngxLjAsIGJuLngyLjApLCANCiAgICAgICAgICAgICAgICAgICBtb2RlID0gIm1hcmtlcnMiLCANCiAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIzZCIsIyJzY2F0dGVyM2QiLCANCiAgICAgICAgICAgICAgICAgICBtYXJrZXIgPSBsaXN0KHNpemUgPSAzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY29sc1sxXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzeW1ib2wgPSAxMDQpKSAlPiUNCiAgICAgICAgICMgYWRkaW5nIHBvaW50cyB3aXRoIGxhYmVsIHkgPTENCiAgICAgICAgIGFkZF90cmFjZSh4ID0gYm4ueDEuMSwgDQogICAgICAgICAgICAgICAgICAgeSA9IGJuLngyLjEsIA0KICAgICAgICAgICAgICAgICAgIHogPSBmZihibi54MS4xLCBibi54Mi4xKSwNCiAgICAgICAgICAgICAgICAgICBtb2RlID0gIm1hcmtlcnMiLCANCiAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIzZCIsIA0KICAgICAgICAgICAgICAgICAgIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xzWzEwXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzeW1ib2wgPSAxMDQpKSAlPiUNCiAgICAgICBsYXlvdXQodGl0bGUgPSAiQml2YXJpYXRlIFNjYXR0ZXIgUGxvdCIsDQogICAgICAgICAgICAgIHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSAieDEiKSwNCiAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIngyIiksDQogICAgICAgICAgICAgIHpheGlzID0gbGlzdCh0aXRsZSA9ICJEZW5zaXR5IikpLA0KICAgICAgICAgICAgICBzaG93bGVnZW5kID0gRkFMU0UNCiAgICAgICAgICklPiUgaGlkZV9jb2xvcmJhcigpIA0KYGBgDQoNClRoZSBub25saW5lYXIgY3VydmUgZm9ybWVkIGJ5IHRoZSBpbnRlcnNlY3Rpb24gb2YgdGhlIDNEIHN1cmZhY2UgYW5kIHRoZSAyRCBwbGFuZSByZXByZXNlbnRzIHRoZSBkZWNpc2lvbiBib3VuZGFyeS4gSXRzIHByb2plY3Rpb24gb250byB0aGUgb3JpZ2luYWwgMkQgZmVhdHVyZSBzcGFjZSBkZWZpbmVzIHRoZSBub25saW5lYXIgc2VwYXJhdGlvbiBib3VuZGFyeS4NCg0KDQoNCg0KIyMjIEtlcm5lbCBEZW5zaXR5IEVzdGltYXRpb24gQXBwcm9hY2gNCg0KRm9yIHRoZSBzZXBhcmF0aW9uIHByb2JsZW0gaW4gYSB0d28tZGltZW5zaW9uYWwgZmVhdHVyZSBzcGFjZSwgbm9ucGFyYW1ldHJpYyBkZW5zaXR5IGVzdGltYXRpb24gbWV0aG9kcyBjYW4gYmUgdXNlZCB0byBlc3RpbWF0ZSB0aGUgZGVuc2l0eSBzdXJmYWNlLiBUaGUgb3B0aW1hbCBub25saW5lYXIgc2VwYXJhdGlvbiBib3VuZGFyeSBjYW4gdGhlbiBiZSBpZGVudGlmaWVkIHVzaW5nIHRoZSBjb250b3VycyBvZiB0aGUgZXN0aW1hdGVkIGRlbnNpdHkgc3VyZmFjZS4gQmVsb3cgaXMgYW4gZXhhbXBsZSBiYXNlZCBvbiB0aGUgc2FtZSBzaW11bGF0ZWQgZGF0YSBmcm9tIHRoZSBwcmV2aW91cyBzdWJzZWN0aW9uLg0KDQoNCmBgYHtyICBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTV9DQpzdXJmYWNlID0ga2RlMmQoYm4uZGF0YSR4MSwgYm4uZGF0YSR4MiwgbiA9IDEwMCkNCnBsb3RfbHkoeCA9IHN1cmZhY2UkeCwgDQogICAgICAgIHkgPSBzdXJmYWNlJHksDQogICAgICAgIHogPSBzdXJmYWNlJHosDQogICAgICAgIHR5cGUgPSAic3VyZmFjZSIsDQogICAgICAgIGNvbnRvdXJzID0gbGlzdCggeiA9IGxpc3Qoc2hvdyA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsICAgICAgICMgc2V0IGNvbnRvdXIgY29sb3INCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGggPSAyLCAgICAgICAgICAgICAjIHNldCBjb250b3VyIHRoaWNrbmVzcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gbWluKHpfbWF0cml4ICksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZCA9IG1heCh6X21hdHJpeCApLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMC4wMTI1KSkpICAgJT4lDQogICAgICAgICAjIGFkZGluZyBpbnRlcnNlY3RpbmcgcGxhbmUNCiAgICAgICAgIGFkZF90cmFjZSh4ID0gIHgxX3JhbmdlLCAgICANCiAgICAgICAgICAgICAgICAgICB5ID0gIHgyX3JhbmdlLCANCiAgICAgICAgICAgICAgICAgICB6ID0gIHowLA0KICAgICAgICAgICAgICAgICAgIGNvbG9ycyA9ICJza3libHVlIiwNCiAgICAgICAgICAgICAgICAgICB0eXBlPSJzdXJmYWNlIiwNCiAgICAgICAgICAgICAgICAgICBvcGFjaXR5ID0gMC41KSAgJT4lIGhpZGVfY29sb3JiYXIoKSANCmBgYA0KDQoNCldlIGNhbiBzZWUgdGhhdCB0aGUgZXN0aW1hdGVkIGRlbnNpdHkgc3VyZmFjZSBpcyBzbGlnaHRseSBkaWZmZXJlbnQgZnJvbSB0aGUgdHJ1ZSBkZW5zaXR5IHN1cmZhY2Ugb2YgdGhlIGJpdmFyaWF0ZSBub3JtYWwgZGlzdHJpYnV0aW9uIGluIHRoZSBwcmV2aW91cyBzdWJzZWN0aW9uLiBUaGUgZm9sbG93aW5nIGNvbnRvdXIgcGxvdCBzaG93cyB0aGUgcG90ZW50aWFsIG5vbmxpbmVhciBzZXBhcmF0aW9uIGJvdW5kYXJ5Lg0KDQoNCmBgYHtyICBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTV9DQojbGlicmFyeShNQVNTKQ0KIyMjIw0KI3BhcihtZnJvdz1jKDEsMikpDQpjb2xzIDwtIGhjbC5jb2xvcnMoMTAsICJ2aXJpZGlzIikNCnBsb3QoYm4uZGF0YSR4MSwgYm4uZGF0YSR4MiwgY29sID0gaWZlbHNlKGJuLmRhdGEkeSA9PSAxLCBjb2xzWzEwXSwgY29sc1sxXSksIHBjaCA9IDE5LA0KICAgICB4bGFiID0gIngxIiwgeWxhYiA9ICJ4MiIsIG1haW4gPSAiQml2YXJpYXRlIEtlcm5lbCBEZW5zaXR5IEVzdGltYXRlZCBTdXJmYWNlIHdpdGggQ29udG91cnMiKQ0KDQpjb250b3VyKGtkZTJkKGJuLmRhdGEkeDEsIGJuLmRhdGEkeDIsIG4gPSAxMDApLCBhZGQgPSBUUlVFLA0KICAgICAgICBsZXZlbCA9IDAuMDEyNSwgbHdkID0gMiwgY29sID0gInB1cnBsZTQiLCBjZXggPSAyKQ0KY29udG91cihrZGUyZChibi5kYXRhJHgxLCBibi5kYXRhJHgyLCBuID0gMTAwKSwgYWRkID0gVFJVRSwNCiAgICAgICAgbGV2ZWwgPSAwLjAyNSwgbHdkID0gMiwgY29sID0gImdvbGQiLCBjZXggPSAyKQ0KYGBgDQoNClRoZSBub25wYXJhbWV0cmljIGFwcHJvYWNoIG9mZmVycyBmbGV4aWJsZSBlc3RpbWF0aW9uIGJ1dCBpcyBzdWJqZWN0IHRvIHBvdGVudGlhbCBtaXNzcGVjaWZpY2F0aW9uLiA8Zm9udCBjb2xvciA9ICJyZWQiPioqSW4gdGhpcyBpbGx1c3RyYXRpdmUgZXhhbXBsZSwgYSBiaXZhcmlhdGUgbm9ybWFsIChHYXVzc2lhbikga2VybmVsIHdhcyB1c2VkIGFzIGEgd2VpZ2h0aW5nIGZ1bmN0aW9uIHRvIGNvbXB1dGUgdGhlIHdlaWdodGVkIGF2ZXJhZ2Ugb2YgYWxsIHBvaW50cywgZGVmaW5pbmcgdGhlIGRlbnNpdHkgKG1vdmluZyBhdmVyYWdlKSBpbiB0aHJlZS1kaW1lbnNpb25hbCBzcGFjZSoqPC9mb250Pi4gPGZvbnQgY29sb3IgPSAiYmx1ZSI+KipIb3dldmVyLCBpbiBzdXBwb3J0IHZlY3RvciBtYWNoaW5lcyAoU1ZNKSwgdGhlIEdhdXNzaWFuIGtlcm5lbCBzZXJ2ZXMgYSBkaWZmZXJlbnQgcHVycG9zZTogaXQgbWFwcyBhIGxvd2VyLWRpbWVuc2lvbmFsIGZlYXR1cmUgc3BhY2UgdG8gYSBoaWdoZXItZGltZW5zaW9uYWwgc3BhY2UsIGVuYWJsaW5nIHRoZSB0cmFuc2Zvcm1hdGlvbiBvZiBhIG5vbmxpbmVhciBzZXBhcmF0aW9uIHByb2JsZW0gaW50byBhIGxpbmVhciBvbmUuKio8L2ZvbnQ+DQoNClwNCg0KIyMjIFNWTSB3aXRoIFJCRiBLZXJuZWwgDQoNCldlIG5vdyB1c2UgUiBgc3ZtKClgIGluIHRoZSBSIGxpYnJhcnkgYGUxMDcxYCB0byBmaW5kIHRoZSBkZWNpc2lvbiAoc2VwYXJhdGlvbikgYm91bmRhcnkgb2YgdGhlIGFib3ZlIHNpbXVsYXRlZCBkYXRhIHNldC4gIA0KDQpgYGB7ciAgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01fQ0KI2xpYnJhcnkoZTEwNzEpDQojbGlicmFyeShnZ3Bsb3QyKQ0KDQojIFRyYWluIFNWTSB3aXRoIFJCRiBrZXJuZWwNCnN2bV9tb2RlbCA8LSBzdm0oeSB+IC4sIGRhdGEgPSBibi5kYXRhLCBrZXJuZWwgPSAicmFkaWFsIiwgZ2FtbWEgPSAxKQ0KIyMNCiMgRGVmaW5lIGEgZ3JpZCBvdmVyIHRoZSBmZWF0dXJlIHNwYWNlDQp4MV9yYW5nZSA8LSBzZXEobWluKGJuLmRhdGEkeDEpLCBtYXgoYm4uZGF0YSR4MSksIGxlbmd0aCA9IDU1KQ0KeDJfcmFuZ2UgPC0gc2VxKG1pbihibi5kYXRhJHgyKSwgbWF4KGJuLmRhdGEkeDIpLCBsZW5ndGggPSA1NSkNCmdyaWQwIDwtIGV4cGFuZC5ncmlkKHgxID0geDFfcmFuZ2UsIHgyID0geDJfcmFuZ2UpDQojIyMjDQojIyMjIFByZWRpY3QgZGVjaXNpb24gdmFsdWVzDQpzdm0ucHJlZCA8LSBwcmVkaWN0KHN2bV9tb2RlbCwgZ3JpZDAsIGRlY2lzaW9uLnZhbHVlcyA9IFRSVUUpDQojIHR1cm4gb3ZlciB0aGUgc3VyZmFjZSBmb3IgZWFzaWVyIHJlYWRpbmcuIGFkZCBhIG5lZ2F0aXZlIHNpZ24gdG8gdGhlIHByZWQgdmFsdWVzLg0KZGVjaXNpb25fdmFsdWVzIDwtIC0gYXR0cmlidXRlcyhzdm0ucHJlZCkkZGVjaXNpb24udmFsdWVzICAgDQpncmlkMCRkZWNpc2lvbl92YWx1ZXMgPC0gZGVjaXNpb25fdmFsdWVzDQp6el9tYXRyaXggPC0gbWF0cml4KGdyaWQwJGRlY2lzaW9uX3ZhbHVlcywgYnlyb3cgPSBUUlVFLCBuY29sPSBsZW5ndGgoeDFfcmFuZ2UpKQ0KIyMjIyMjIyMjIyMjIw0KIyMjIyMjIyMjIyMjIw0KIyMjIDNEIGRhdGEgcG9pbnRzIHBsb3R0aW5nIA0KZml0dGVkLnN2bSA8LSBwcmVkaWN0KHN2bV9tb2RlbCwgYm4uZGF0YVssLTNdLCBkZWNpc2lvbi52YWx1ZXMgPSBUUlVFKQ0KIyByZXZlcnNlIHByZWRpY3RlZCB6IGZvciBkYXRhIHBvaW50cw0KZml0dGVkLnkudmFsIDwtIC0gYXR0cmlidXRlcyhmaXR0ZWQuc3ZtKSRkZWNpc2lvbi52YWx1ZXMgICANCiMgZGF0YSRmaXR0ZWQueS52YWwgPC0gZml0dGVkLnkudmFsDQpkYXRhLnBvaW50cyA8LSBkYXRhLmZyYW1lKHgxID0gYm4uZGF0YSR4MSwgeDIgPSBibi5kYXRhJHgyLCBwcmVkLnkgPWZpdHRlZC55LnZhbCApDQoNCiMjIyBwbG90IHRoZSBwb2ludHMgaW4gdGhlIDJEIGZlYXR1cmUgc3BhY2UNCnkgPC0gaWZlbHNlKGZpdHRlZC55LnZhbCAgPiAwLCAxLCAwKSAgICAgIyBkZWZpbmUgdGhlIGxhYmVsIG9mIHRoZSAyRCBwb2ludHMNCiMjIyB3b3JraW5nIGRhdGEgc2V0ICMgeSBpcyByZXNwb25zZSBsYWJlbA0Kc3ZtLmRhdGEgPC0gZGF0YS5mcmFtZSh4MSA9IHgxMCwgeDIgPSB4MjAsIHp6ID0gZml0dGVkLnkudmFsLCB5ID0gYXMuZmFjdG9yKHkpKSAgIA0KIyMjIHBvaW50cyB3aXRoIGxhYmVsIHkgPSAwDQpzdm0uZGF0YTAgPC0gc3ZtLmRhdGFbc3ZtLmRhdGEkeSA9PSAwLCBdDQpzdm0ueDEuMCA8LSBzdm0uZGF0YTAkeDEgDQpzdm0ueDIuMCA8LSBzdm0uZGF0YTAkeDINCnN2bS56LjAgPC0gc3ZtLmRhdGEwJFgwLjENCiMjIyBwb2ludHMgd2l0aCBsYWJlbCB5ID0gMQ0Kc3ZtLmRhdGExIDwtc3ZtLmRhdGFbc3ZtLmRhdGEkeSA9PSAxLCBdDQpzdm0ueDEuMSA8LSBzdm0uZGF0YTEkeDENCnN2bS54Mi4xIDwtIHN2bS5kYXRhMSR4Mg0Kc3ZtLnouMSA8LSBzdm0uZGF0YTEkWDAuMQ0KIyMjIyMjIyMjIyMjIw0KIyMjIFNlcGFyYXRpbmcgcGxhbmUNCmZmMCA8LSBmdW5jdGlvbih4MSwgeDIpIHswICsgMCp4MSArIDAqeDJ9ICAgIyBEZW5zaXR5IGZ1bmN0aW9uDQp6MCA8LSBvdXRlcih4MV9yYW5nZSwgeDJfcmFuZ2UsIGZmMCkgDQoNCiMjIw0KIyBFeHRyYWN0IHNwZWNpZmljIGNvbnRvdXIgKGUuZy4sIGF0IGxldmVsIHogPSAwLjUpDQpjb250b3VyX2RhdGEgPC0gY29udG91ckxpbmVzKHgxX3JhbmdlLCB4Ml9yYW5nZSwgenpfbWF0cml4LCBsZXZlbHMgPSAwKQ0KDQojIENvbnZlcnQgY29udG91ciBkYXRhIHRvIGEgZGF0YSBmcmFtZQ0KY29udG91cl9kZiA8LSBkby5jYWxsKHJiaW5kLCBsYXBwbHkoY29udG91cl9kYXRhLCBmdW5jdGlvbihjbCkgew0KICBkYXRhLmZyYW1lKHggPSBjbCR4LCB5ID0gY2wkeSwgeiA9IHJlcCgwLjUsIGxlbmd0aChjbCR4KSkpICMgQ29uc3RhbnQgeiBsZXZlbA0KfSkpDQojIyMjIyMjIyMjIyMNCg0KIyMgM0QgU3VyZmFjZSBQbG90DQpwbG90X2x5KHggPSB4MV9yYW5nZSwgDQogICAgICAgIHkgPSB4Ml9yYW5nZSwNCiAgICAgICAgeiA9IHp6X21hdHJpeCwgDQogICAgICAgIHR5cGUgPSAic3VyZmFjZSIsDQogICAgICAgIGNvbnRvdXJzID0gbGlzdCggeiA9IGxpc3Qoc2hvdyA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImJyb3duIiwgICAgICAgIyBzZXQgY29udG91ciBjb2xvcg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoID0gNCwgICAgICAgICAgICAgIyBzZXQgY29udG91ciB0aGlja25lc3MNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjc3RhcnQgPSBtaW4oenpfbWF0cml4ICksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNlbmQgPSBtYXgoenpfbWF0cml4ICksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IDApKSkgICAlPiUNCiMpICAgICU+JQ0KICAgICAgICAgIyBhZGRpbmcgaW50ZXJzZWN0aW5nIHBsYW5lDQogICAgICAgICBhZGRfdHJhY2UoeCA9ICB4MV9yYW5nZSwgICAgDQogICAgICAgICAgICAgICAgICAgeSA9ICB4Ml9yYW5nZSwgDQogICAgICAgICAgICAgICAgICAgeiA9ICB6MCwNCiAgICAgICAgICAgICAgICAgICBjb2xvcnMgPSAic3RlZWxibHVlIiwNCiAgICAgICAgICAgICAgICAgICB0eXBlPSJzdXJmYWNlIiwNCiAgICAgICAgICAgICAgICAgICBvcGFjaXR5ID0gMC41KSAgICU+JQ0KICAgICAgICAgIyBhZGRpbmcgcG9pbnRzIHdpdGggbGFiZWwgeSA9IDANCiAgICAgICAgIGFkZF90cmFjZSh4ID0gc3ZtLngxLjAsICAgIA0KICAgICAgICAgICAgICAgICAgIHkgPSBzdm0ueDIuMCwgDQogICAgICAgICAgICAgICAgICAgeiA9IHN2bS56LjAsIA0KICAgICAgICAgICAgICAgICAgIG1vZGUgPSAibWFya2VycyIsIA0KICAgICAgICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlcjNkIiwjInNjYXR0ZXIzZCIsIA0KICAgICAgICAgICAgICAgICAgIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xzWzFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5bWJvbCA9IDEwNCkpICU+JQ0KICAgICAgICAgIyBhZGRpbmcgcG9pbnRzIHdpdGggbGFiZWwgeSA9MQ0KICAgICAgICAgYWRkX3RyYWNlKHggPSBzdm0ueDEuMSwgDQogICAgICAgICAgICAgICAgICAgeSA9IHN2bS54Mi4xLCANCiAgICAgICAgICAgICAgICAgICB6ID0gc3ZtLnouMSwNCiAgICAgICAgICAgICAgICAgICBtb2RlID0gIm1hcmtlcnMiLCANCiAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIzZCIsIA0KICAgICAgICAgICAgICAgICAgIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xzWzEwXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzeW1ib2wgPSAxMDQpKSAlPiUNCiAgICAgICBsYXlvdXQodGl0bGUgPSAiU1ZNIFByZWRpY3RlZCAzRCBTY2F0dGVyIFBsb3QiLA0KICAgICAgICAgICAgICBzY2VuZSA9IGxpc3QoeGF4aXMgPSBsaXN0KHRpdGxlID0gIngxIiksDQogICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJ4MiIpLA0KICAgICAgICAgICAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSAiRGVuc2l0eSIpKSwNCiAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFDQogICAgICAgICApICU+JSBoaWRlX2NvbG9yYmFyKCkgDQoNCmBgYA0KDQoNClRoZSBub25saW5lYXIgZGVjaXNpb24gYm91bmRhcnkgaXMgZGVwaWN0ZWQgaW4gdGhlIGZvbGxvd2luZyBmaWd1cmUuDQoNCg0KYGBge3IgIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NX0NCmdnc3ZtIDwtIGdncGxvdChkYXRhLCBhZXMoeDEsIHgyLCBjb2xvciA9IHkpKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIjAiID0gY29sc1sxXSwgIjEiID0gY29sc1sxMF0pKSArDQogIGxhYnModGl0bGUgPSAiU1ZNIENsYXNzaWZpY2F0aW9uIHdpdGggUkJGIiwNCiAgICAgICB4ID0gIlgtYXhpcyIsDQogICAgICAgeSA9ICJZLWF4aXMiLA0KICAgICAgIGNvbG9yID0gIkNhdGVnb3J5IikgKw0KICBnZW9tX2NvbnRvdXIoZGF0YSA9IGdyaWQwLCBhZXMoeCA9IHgxLCB5ID0geDIsIHogPSBhcy5udW1lcmljKGRlY2lzaW9uX3ZhbHVlcykpLCANCiAgICAgICAgICAgICAgIGJyZWFrcyA9IDAsIGNvbG9yID0gInB1cnBsZTQiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KZ2dwbG90bHkoZ2dzdm0pDQpgYGANCg0KDQojIEhhbmRpbmcgQ2F0ZWdvcmljYWwgRmVhdHVyZXMNCg0KVGhlIGV4YW1wbGVzIGFuZCBpbGx1c3RyYXRpb25zIG9mIFNWTSBkaXNjdXNzZWQgZWFybGllciBhcmUgYmFzZWQgb24gbnVtZXJpY2FsIGZlYXR1cmVzLiBXaGVuIGRlYWxpbmcgd2l0aCBjYXRlZ29yaWNhbCBmZWF0dXJlcywgd2UgbmVlZCB0byBjb252ZXJ0IHRoZW0gaW50byBudW1lcmljYWwgcmVwcmVzZW50YXRpb25zLiBCZWxvdyBhcmUgc29tZSBjb21tb24gdGVjaG5pcXVlcyBmb3IgaGFuZGxpbmcgY2F0ZWdvcmljYWwgZmVhdHVyZXMgaW4gU1ZNLg0KDQoNCiMjIE9uZS1Ib3QgRW5jb2RpbmcNCk9uZS1ob3QgZW5jb2RpbmcgY29udmVydHMgZWFjaCBjYXRlZ29yaWNhbCBmZWF0dXJlIGludG8gYSBiaW5hcnkgdmVjdG9yLCB3aGVyZSBlYWNoIGNhdGVnb3J5IGlzIHJlcHJlc2VudGVkIGFzIGEgYmluYXJ5IGNvbHVtbi4NCg0KQW4gaWxsdXN0cmF0aXZlIGV4YW1wbGUgaW4gUjoNCg0KYGBge3IgIGVjaG8gPSBUUlVFfQ0KIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJ5DQojbGlicmFyeShlMTA3MSkgICMgRm9yIFNWTQ0KI2xpYnJhcnkoY2FyZXQpICAjIEZvciBkYXRhIHByZXByb2Nlc3NpbmcNCg0KIyBFeGFtcGxlIGRhdGFzZXQNCmRhdGEgPC0gZGF0YS5mcmFtZSgNCiAgZmVhdHVyZTEgPSBjKCJBIiwgIkIiLCAiQSIsICJDIiksDQogIGZlYXR1cmUyID0gYygiWCIsICJZIiwgIlgiLCAiWiIpLA0KICB0YXJnZXQgPSBjKDEsIDAsIDEsIDApDQopDQoNCiMgT25lLWhvdCBlbmNvZGluZw0KZHVtbXkgPC0gZHVtbXlWYXJzKCIgfiAuIiwgZGF0YSA9IGRhdGEpDQpkYXRhX2VuY29kZWQgPC0gZGF0YS5mcmFtZShwcmVkaWN0KGR1bW15LCBuZXdkYXRhID0gZGF0YSkpDQojIFZpZXcgZW5jb2RlZCBkYXRhDQpwcmludChkYXRhX2VuY29kZWQpDQojIFRyYWluIFNWTQ0KI3N2bV9tb2RlbCA8LSBzdm0odGFyZ2V0IH4gLiwgZGF0YSA9IGRhdGFfZW5jb2RlZCwga2VybmVsID0gImxpbmVhciIpDQojc3VtbWFyeShzdm1fbW9kZWwpDQpgYGANCg0KT25lLWhvdCBlbmNvZGluZyBpcyB0aGUgbW9zdCBjb21tb24gbWV0aG9kIGJ1dCBjYW4gbGVhZCB0byBoaWdoIGRpbWVuc2lvbmFsaXR5IGZvciBmZWF0dXJlcyB3aXRoIG1hbnkgY2F0ZWdvcmllcy4NCg0KDQojIyBMYWJlbCBFbmNvZGluZw0KDQpMYWJlbCBlbmNvZGluZyBhc3NpZ25zIGEgdW5pcXVlIGludGVnZXIgdG8gZWFjaCBjYXRlZ29yeS4gVGhpcyBpcyB1c2VmdWwgZm9yIG9yZGluYWwgY2F0ZWdvcmljYWwgZmVhdHVyZXMuDQoNCkFuIGlsbHVzdHJhdGl2ZSBleGFtcGxlIGluIFI6DQoNCmBgYHtyICBlY2hvID0gVFJVRX0NCiMgRXhhbXBsZSBkYXRhc2V0DQpkYXRhIDwtIGRhdGEuZnJhbWUoDQogIGZlYXR1cmUxID0gYygiTG93IiwgIk1lZGl1bSIsICJIaWdoIiwgIkxvdyIpLA0KICBmZWF0dXJlMiA9IGMoIlNtYWxsIiwgIkxhcmdlIiwgIk1lZGl1bSIsICJTbWFsbCIpLA0KICB0YXJnZXQgPSBjKDEsIDAsIDEsIDApDQopDQoNCiMgTGFiZWwgZW5jb2RpbmcNCmRhdGEkZmVhdHVyZTEgPC0gYXMubnVtZXJpYyhmYWN0b3IoZGF0YSRmZWF0dXJlMSwgbGV2ZWxzID0gYygiTG93IiwgIk1lZGl1bSIsICJIaWdoIikpKQ0KZGF0YSRmZWF0dXJlMiA8LSBhcy5udW1lcmljKGZhY3RvcihkYXRhJGZlYXR1cmUyLCBsZXZlbHMgPSBjKCJTbWFsbCIsICJNZWRpdW0iLCAiTGFyZ2UiKSkpDQoNCiMgVmlldyBlbmNvZGVkIGRhdGENCnByaW50KGRhdGEpDQoNCiMgVHJhaW4gU1ZNDQojc3ZtX21vZGVsIDwtIHN2bSh0YXJnZXQgfiAuLCBkYXRhID0gZGF0YSwga2VybmVsID0gImxpbmVhciIpDQojc3VtbWFyeShzdm1fbW9kZWwpDQpgYGANCg0KTGFiZWwgZW5jb2RpbmcgaXMgc3VpdGFibGUgZm9yIG9yZGluYWwgZGF0YSBidXQgbWF5IGludHJvZHVjZSB1bmludGVuZGVkIG9yZGluYWxpdHkgZm9yIG5vbWluYWwgZGF0YS4NCg0KDQojIyBGcmVxdWVuY3kgRW5jb2RpbmcNCg0KRnJlcXVlbmN5IGVuY29kaW5nIHJlcGxhY2VzIGVhY2ggY2F0ZWdvcnkgd2l0aCBpdHMgZnJlcXVlbmN5IGluIHRoZSBkYXRhc2V0Lg0KDQpBbiBpbGx1c3RyYXRpdmUgZXhhbXBsZSBpbiBSOg0KDQpgYGB7ciAgZWNobyA9IFRSVUV9DQojIEV4YW1wbGUgZGF0YXNldA0KZGF0YSA8LSBkYXRhLmZyYW1lKA0KICBmZWF0dXJlMSA9IGMoIkEiLCAiQiIsICJBIiwgIkMiKSwNCiAgZmVhdHVyZTIgPSBjKCJYIiwgIlkiLCAiWCIsICJaIiksDQogIHRhcmdldCA9IGMoMSwgMCwgMSwgMCkNCikNCg0KIyBGcmVxdWVuY3kgZW5jb2RpbmcNCmZyZXFfZW5jb2RpbmcgPC0gZnVuY3Rpb24oY29sdW1uKSB7DQogIGZyZXEgPC0gdGFibGUoY29sdW1uKQ0KICByZXR1cm4oYXMubnVtZXJpYyhmcmVxW2NvbHVtbl0pKQ0KfQ0KDQpkYXRhJGZlYXR1cmUxIDwtIGZyZXFfZW5jb2RpbmcoZGF0YSRmZWF0dXJlMSkNCmRhdGEkZmVhdHVyZTIgPC0gZnJlcV9lbmNvZGluZyhkYXRhJGZlYXR1cmUyKQ0KDQojIFZpZXcgZW5jb2RlZCBkYXRhDQpwcmludChkYXRhKQ0KDQojIFRyYWluIFNWTQ0KI3N2bV9tb2RlbCA8LSBzdm0odGFyZ2V0IH4gLiwgZGF0YSA9IGRhdGEsIGtlcm5lbCA9ICJsaW5lYXIiKQ0KI3N1bW1hcnkoc3ZtX21vZGVsKQ0KYGBgDQoNCkZyZXF1ZW5jeSBlbmNvZGluZyBhbmQgdGFyZ2V0IGVuY29kaW5nIGFyZSB1c2VmdWwgZm9yIHJlZHVjaW5nIGRpbWVuc2lvbmFsaXR5IGJ1dCBtYXkgbGVhZCB0byBvdmVyZml0dGluZyBpZiBub3QgcmVndWxhcml6ZWQuDQoNCg0KIyMgVGFyZ2V0IEVuY29kaW5nDQpUYXJnZXQgZW5jb2RpbmcgcmVwbGFjZXMgZWFjaCBjYXRlZ29yeSB3aXRoIHRoZSBtZWFuIG9mIHRoZSB0YXJnZXQgdmFyaWFibGUgZm9yIHRoYXQgY2F0ZWdvcnkuIFRoaXMgaXMgdXNlZnVsIGZvciBzdXBlcnZpc2VkIGxlYXJuaW5nIHRhc2tzLg0KDQpBbiBpbGx1c3RyYXRpdmUgZXhhbXBsZSBpbiBSOg0KDQpgYGB7ciBlY2hvID0gVFJVRX0NCiMgRXhhbXBsZSBkYXRhc2V0DQpkYXRhIDwtIGRhdGEuZnJhbWUoDQogIGZlYXR1cmUxID0gYygiQSIsICJCIiwgIkEiLCAiQyIpLA0KICBmZWF0dXJlMiA9IGMoIlgiLCAiWSIsICJYIiwgIloiKSwNCiAgdGFyZ2V0ID0gYygxLCAwLCAxLCAwKQ0KKQ0KDQojIFRhcmdldCBlbmNvZGluZw0KdGFyZ2V0X2VuY29kaW5nIDwtIGZ1bmN0aW9uKGNvbHVtbiwgdGFyZ2V0KSB7DQogIG1lYW5fdGFyZ2V0IDwtIHRhcHBseSh0YXJnZXQsIGNvbHVtbiwgbWVhbikNCiAgcmV0dXJuKG1lYW5fdGFyZ2V0W2NvbHVtbl0pDQp9DQoNCmRhdGEkZmVhdHVyZTEgPC0gdGFyZ2V0X2VuY29kaW5nKGRhdGEkZmVhdHVyZTEsIGRhdGEkdGFyZ2V0KQ0KZGF0YSRmZWF0dXJlMiA8LSB0YXJnZXRfZW5jb2RpbmcoZGF0YSRmZWF0dXJlMiwgZGF0YSR0YXJnZXQpDQoNCiMgVmlldyBlbmNvZGVkIGRhdGENCnByaW50KGRhdGEpDQoNCiMgVHJhaW4gU1ZNDQojc3ZtX21vZGVsIDwtIHN2bSh0YXJnZXQgfiAuLCBkYXRhID0gZGF0YSwga2VybmVsID0gImxpbmVhciIpDQojc3VtbWFyeShzdm1fbW9kZWwpDQpgYGANCg0KDQojIFNWTSBDbGFzc2lmaWNhdGlvbiBBbGdvcml0aG1zDQoNCg0KSGFyZCBtYXJnaW4gYW5kIHNvZnQgbWFyZ2luIGFyZSBpbmRlZWQgY29yZSBjb25jZXB0cyBpbiBTdXBwb3J0IFZlY3RvciBNYWNoaW5lcyAoU1ZNKSwgYW5kIHRoZXkgZGV0ZXJtaW5lIGhvdyBzdHJpY3RseSB0aGUgbW9kZWwgZW5mb3JjZXMgdGhlIHNlcGFyYXRpb24gb2YgZGF0YSBwb2ludHMgaW50byB0aGVpciByZXNwZWN0aXZlIGNsYXNzZXMuIFRoZXkgYXJlIGNlbnRyYWwgdG8gdW5kZXJzdGFuZGluZyBob3cgU1ZNcyBoYW5kbGUgbGluZWFybHkgc2VwYXJhYmxlIGFuZCBub24tbGluZWFybHkgc2VwYXJhYmxlIGRhdGEuIA0KDQoNCkZvciBlYXNlIG9mIHByZXNlbnRhdGlvbiwgd2UgdXNlIHRoZSBsaW5lYXIgU1ZNIGZvciBjbGFzc2lmaWNhdGlvbiBhcyBhbiBleGFtcGxlIHRvIGV4cGxhaW4gdGhlIGNvbmNlcHQgb2Ygc29mdCBhbmQgaGFyZCBtYXJnaW5zIGFuZCB0aGUgZm9ybXVsYXRpb24gb2YgU1ZNLiAgTm90ZSB0aGF0IHRoZSBkaXN0YW5jZSBiZXR3ZWVuIHR3byBwYXJhbGxlbCBoeXBlcnBsYW5lcyBpbiBhIGstZGltZW5zaW9uYWwgc3BhY2UsIGRlbm90ZWQgYnkNCg0KJCQNCkxfMTogXCAgYV8xIHhfMSArYV8yIHhfMiArIFxjZG90cyArIGFfayB4X2sgKyBkXzEgPSAwDQokJA0KYW5kDQoNCiQkDQpMXzI6IFwgIGFfMSB4XzEgK2FfMiB4XzIgKyBcY2RvdHMgKyBhX2sgeF9rICsgZF8yID0gMCwNCiQkDQoNCmlzIGdpdmVuIGJ5DQoNCiQkDQp8TF8xTF8yfCA9IFxmcmFje3xkXzItZF8xfH17XHNxcnR7YV8xXjIgKyBhXzJeMiArIFxjZG90cyArIGFfa14yfX0NCiQkDQoNCg0KIyMgIEhhcmQgTWFyZ2luIFNWTQ0KDQpXaXRob3V0IGxvc3Mgb2YgZ2VuZXJhbGl0eSwgd2UgY29uc2lkZXIgdGhlIGxpbmVhciBzZXBhcmF0aW9uIHByb2JsZW0gaW4gMiBkaW1lbnNpb25hbCBmZWF0dXJlIHNwYWNlLg0KDQpUaGUgZ29hbCBpcyB0byBmaW5kIHRoZSBoeXBlcnBsYW5lIHRoYXQgbWF4aW1pemVzIHRoZSBtYXJnaW4gKHRoZSBkaXN0YW5jZSBiZXR3ZWVuIHRoZSB0d28gKipwYXJhbGxlbCBoeXBlcnBsYW5lcyoqIGFuZCB0aGUgbmVhcmVzdCBkYXRhIHBvaW50cyBmcm9tIGVhY2ggY2xhc3MpIHdoaWxlIGVuc3VyaW5nIHRoYXQgYWxsIGRhdGEgcG9pbnRzIGFyZSBjb3JyZWN0bHkgY2xhc3NpZmllZC4gIEluIHRoZSB0d28gZGltZW5zaW9uYWwgZmVhdHVyZSBzcGFjZSwgdGhlIHR3byAqKnBhcmFsbGVsIGh5cGVycGxhbmVzKiogYXJlIGRlbm90ZWQgYnkgcmVzcGVjdGl2ZWx5DQoNCiQkDQp3XzF4XzEgKyB3XzIgeF8yICsgYiA9ICsxICBcICBcICBcdGV4dHthbmR9IFwgXCAgd18xeF8xICsgd18yeF8yICsgYiA9IC0xLg0KJCQNCg0KVGhlIGNvZWZmaWNpZW50cyBvZiAkeF8xJCBhbmQgJHhfMiQgb2YgdHdvIGV4cHJlc3Npb25zIGFyZSBpZGVudGljYWwgYmVjYXVzZSB0aGV5IGFyZSBwYXJhbGxlbC4gV2l0aCB0aGUgYWJvdmUgKm5vbi1zdGFuZGFyZCBub3RhdGlvbiosICBgdGhlIGh5cGVycGxhbmVgICR3XzF4XzEgKyB3XzIgeF8yICsgYiA9ICsxJCBpcyBjbG9zZXIgdG8gdGhlIGdyb3VwIHdpdGggbGFiZWwgKiokeSA9ICsxJCoqLCB3aGlsZSAkd18xeF8xICsgd18yIHhfMiArIGIgPSAtMSQgaXMgY2xvc2VyIHRvIHRoZSBncm91cCB3aXRoIGxhYmVsICoqJHkgPSAtMSQqKi4gQ29uc2VxdWVudGx5LCAkd18xeF8xICsgd18yIHhfMiArIGIgPSArMSQgaXMgcmVmZXJyZWQgdG8gYXMgdGhlICoqUG9zaXRpdmUgTWFyZ2luIEh5cGVycGxhbmUqKiBhbmQgJHdfMXhfMSArIHdfMiB4XzIgKyBiID0gLTEkIGFzIHRoZSAqKk5lZ2F0aXZlIE1hcmdpbiBIeXBlcnBsYW5lKiouDQoNCg0KDQoNCklmIHdlIGludHJvZHVjZSB0aGUgZm9sbG93aW5nIGNvbHVtbiB2ZWN0b3Igbm90YXRpb25zDQoNCiQkDQpcbWF0aGJme3d9ID0gXGJlZ2lue2JtYXRyaXh9IA0KICAgICAgICAgICAgICAgICAgICAgICAgd18xICAgXFwNCiAgICAgICAgICAgICAgICAgICAgICAgIHdfMiAgDQogICAgICAgICAgICAgICAgICBcZW5ke2JtYXRyaXh9ICBcIFwgXHRleHR7YW5kfSBcIFwgDQpcbWF0aGJme3h9ICA9IFxiZWdpbntibWF0cml4fSANCiAgICAgICAgICAgICAgICAgICAgICAgIHhfMSBcXA0KICAgICAgICAgICAgICAgICAgICAgICAgeF8yDQogICAgICAgICAgICAgICAgICBcZW5ke2JtYXRyaXh9LA0KJCQNCg0Kd2UgY2FuIHJlLWV4cHJlc3MgaW4gdGhlIGZvbGxvd2luZyB2ZWN0b3IgZm9ybQ0KDQokJA0KIFxtYXRoYmZ7d15UeH0gKyBiID0gMSAgXCAgXCAgXHRleHR7YW5kfSBcIFwgIFxtYXRoYmZ7d15UeH0gKyBiID0gLTEuDQokJA0KDQoNClVzaW5nIHRoZSBhYm92ZSBub3RhdGlvbnMsIHdlIHN1bW1hcml6ZSB0aGUgcG9zaXRpdmUgYW5kIG5lZ2F0aXZlIGh5cGVycGxhbmVzIGluIHRoZSBmb2xsb3dpbmcgZmlndXJlLg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIG91dC53aWR0aD0iNjAlIn0NCmluY2x1ZGVfZ3JhcGhpY3MoImltZy9IYXJkTWFyZ2luLnBuZyIpDQpgYGANCg0KQmFzZWQgb24gdGhlIGZvcm11bGEgb2YgZGlzdGFuY2UgYmV0d2VlbiB0d28gcGFyYWxsZWwgbGluZXMgKGkuZS4sIHRoZSAyRCBoeXBlcnBsYW5lcyksIHRoZSBwcm9ibGVtIG9mIG1heGltaXppbmcgdGhlIG1hcmdpbiAkMi98fFxtYXRoYmZ7d318fF8yJCBpcyBleHByZXNzZWQgaW4gdGhlIGZvbGxvd2luZyBlcXVpdmFsZW50IGV4cHJlc3Npb25zDQoNCiQkDQpcbWF4X3tcbWF0aGJme3d9LGJ9XGZyYWN7Mn17fHxcbWF0aGJme3d9fHxeMl8yfSBccmlnaHRhcnJvdyBcbWF4X3tcbWF0aGJme3d9LGJ9XGZyYWN7MX17fHxcbWF0aGJme3d9fHxeMl8yfSBccmlnaHRhcnJvdyBcbWluX3tcbWF0aGJme3d9LGJ9fHxcbWF0aGJme3d9fHxeMl8yLg0KJCQNCg0KVGhhdCBpcywgdGhlIGFib3ZlIG9wdGltaXphdGlvbiBwcm9ibGVtIGlzIHRvIGVzdGltYXRlICRcbWF0aGJme3d9ID0gKHdfMSwgd18yKSQgYW5kICRiJCB0aGF0ICoqbWF4aW1pemUqKiB0aGUgbWFyZ2luICQyL3x8XG1hdGhiZnt3fXx8XzIkIG9yICoqbWluaW1pemUqKiAkfHxcbWF0aGJme3d9fHxfMiQuIFRoaXMgb3B0aW1pemF0aW9uIHdpbGwgYmUgcGVyZm9ybWVkIHVzaW5nIHNvZnR3YXJlIHByb2dyYW1zIHN1Y2ggYXMgUiBmdW5jdGlvbiBgc3ZtKClgIGluIFIgbGlicmFyeSBgTUFTU2AuIA0KDQpPbmNlICRcbWF0aGJme3d9ID0gKHdfMSwgd18yKSQgYW5kICRiJCBhcmUgZXN0aW1hdGVkIGZyb20gdGhlIGRhdGEsIHRoZSAqKmNlbnRlciBoeXBlcnBsYW5lKiogYmV0d2VlbiB0aGUgdHdvIHBhcmFsbGVsIGh5cGVycGxhbmVzLCAqKnRoZSBkZXNpcmVkIGRlY2lzaW9uIGJvdW5kYXJ5IC0gJFxtYXRoYmZ7d15UeH0gKyBiID0gMCQgKiosIGlzIHVuaXF1ZWx5IGRldGVybWluZWQuDQoNCg0KRmluYWxseSwgdGhlIG9iamVjdGl2ZSBmdW5jdGlvbiBvZiBtYXhpbWl6aW5nIGhhcmQtbWFyZ2luIGluIFNWTSBpcyBnaXZlbiBieQ0KDQokJA0KXG1pbl97XG1hdGhiZnt3fSxifSB8fFxtYXRoYmZ7d318fF4yDQokJA0KDQpzdWJqZWN0aW5nIHRvIHRoZSBjb25zdHJhaW50IHRoYXQgYWxsIGRhdGEgcG9pbnRzIGFyZSBjb3JyZWN0bHkgY2xhc3NpZmllZA0KDQokJA0KeV9pKFxtYXRoYmZ7d31eVFxtYXRoYmZ7eH1faSArIGIpIFxnZSAxIFwgXCBcdGV4dHtmb3IgYW55fSBcIFwgaS4gDQokJA0KDQp3aGVyZSAkeV9pJCBpcyB0aGUgbGFiZWwgb2YgJGkkLXRoIGRhdGEgcG9pbnQgdGFraW5nIHZhbHVlcyAkKzEkIG9yICQtMSQuIA0KDQoNClwNCg0KIyMgU29mdCBNYXJnaW46IEMtY2xhc3NpZmljYXRpb24NCg0KDQpTb2Z0IG1hcmdpbiBTVk0gaXMgdXNlZCB3aGVuIHRoZSBkYXRhIGlzICoqbm90IGxpbmVhcmx5IHNlcGFyYWJsZSoqIG9yIGNvbnRhaW5zIG5vaXNlLiA8Zm9udCBjb2xvciA9ICJyZWQiPkl0IGFsbG93cyBmb3Igc29tZSBtaXNjbGFzc2lmaWNhdGlvbiBieSBpbnRyb2R1Y2luZyAqKnNsYWNrIHZhcmlhYmxlcyAoJFx4aV9pJCkqKiB0aGF0IG1lYXN1cmUgdGhlIGRlZ3JlZSBvZiBtaXNjbGFzc2lmaWNhdGlvbiBmb3IgZWFjaCBkYXRhIHBvaW50PC9mb250Pi4gVGhlIGdvYWwgaXMgdG8gbWF4aW1pemUgdGhlIG1hcmdpbiB3aGlsZSBtaW5pbWl6aW5nIHRoZSBzdW0gb2YgdGhlc2Ugc2xhY2sgdmFyaWFibGVzLg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIG91dC53aWR0aD0iNjAlIn0NCmluY2x1ZGVfZ3JhcGhpY3MoImltZy9Tb2Z0TWFyZ2luLnBuZyIpDQpgYGANCg0KV2UgY2FuIHNlZSBmcm9tIHRoZSBhYm92ZSBmaWd1cmUgdGhhdCAkMCA8IFx4aV8xIDwgMSQgYW5kICRceGlfMiwgXHhpXzMgPiAxJC4NCg0KDQpUaGUgZXN0aW1hdGlvbiBvZiB0aGUgdW5rbm93biBwYXJhbWV0ZXJzIGluIHRoZSBTVk0gYWxnb3JpdGhtIGlzIHRoZSBmb2xsb3dpbmcgb3B0aW1pemF0aW9uLg0KDQokJA0KXG1pbl97XG1hdGhiZnt3fSxifSBcbGVmdCggfHxcbWF0aGJme3d9fHxeMiArIENcc3VtX3tpPTF9Xm4gXHhpX2lccmlnaHQpDQokJA0KDQpTdWJqZWN0IHRvIHRoZSBjb25zdHJhaW50IHRoYXQgYWxsIGRhdGEgcG9pbnRzIGFyZSBjb3JyZWN0bHkgY2xhc3NpZmllZA0KDQokJA0KeV9pKFxtYXRoYmZ7d31eVFxtYXRoYmZ7eH1faSArIGIpIFxnZSAxIC0gXHhpX2kgXCBcIFx0ZXh0e2ZvciBhbnl9IFwgXCBpLiANCiQkDQoNCndoZXJlICRceGlfaSBcZ2UgMCQgYW5kICAkeV9pJCBpcyB0aGUgbGFiZWwgb2YgJGkkLXRoIGRhdGEgcG9pbnQgdGFraW5nIHZhbHVlcyAkKzEkIG9yICQtMSQuICRDJCBpcyBhIHJlZ3VsYXJpemF0aW9uIHBhcmFtZXRlciB0aGF0IGNvbnRyb2xzIHRoZSB0cmFkZS1vZmYgYmV0d2VlbiBtYXhpbWl6aW5nIHRoZSBtYXJnaW4gYW5kIG1pbmltaXppbmcgdGhlIGNsYXNzaWZpY2F0aW9uIGVycm9yLg0KDQoNClRoZSAqKnNsYWNrIHZhcmlhYmxlICR4aV9pJCoqIGlzIGEgbWVhc3VyZSBvZiBob3cgbXVjaCBhIHBvaW50IHZpb2xhdGVzIHRoZSBoYXJkIG1hcmdpbiBjb25zdHJhaW50LiANCg0KKiBDb3JyZWN0bHkgY2xhc3NpZmllZCBwb2ludHMgb3V0c2lkZSB0aGUgbWFyZ2luIHdpbGwgaGF2ZSAkXHhpX2kgPSAwJC4NCg0KKiBDb3JyZWN0bHkgY2xhc3NpZmllZCBwb2ludHMgd2l0aGluIHRoZSBtYXJnaW4gd2lsbCBoYXZlICQwIDwgXHhpX2kgPCAxJC4NCg0KKiBNaXNjbGFzc2lmaWVkIHBvaW50cyB3aWxsIGhhdmUgJFx4aV9pID4xJC4NCg0KVGhlIHN1cHBvcnQgdmVjdG9yIG1hY2hpbmUgYmFzZWQgb24gbWF4aW1pemluZyBzb2Z0IG1hcmdpbiBpcyBhbHNvIGNhbGxlZCAqKkMtQ2xhc3NpZmljYXRpb24qKiB0byBoaWdobGlnaHQgdGhlIGltcG9ydGFuY2Ugb2YgdGhlIHJlZ3VsYXJpemF0aW9uIHBhcmFtZXRlciAkQyQuICANCg0KDQpUaGUgcmVndWxhcml6YXRpb24gcGFyYW1ldGVyICRDJCBpbiBTVk0gaXMgaW5kZWVkIGEgKipoeXBlcnBhcmFtZXRlcioqIHRoYXQgbmVlZHMgdG8gYmUgdHVuZWQgdG8gYWNoaWV2ZSB0aGUgYmVzdCBwZXJmb3JtYW5jZSBmb3IgYSBzcGVjaWZpYyBkYXRhc2V0LiBJdCBpcyBub3Qgc29tZXRoaW5nIHRoYXQgaXMgbGVhcm5lZCBkdXJpbmcgdHJhaW5pbmcgYnV0IHJhdGhlciBzZXQgYmVmb3JlIHRyYWluaW5nIGJlZ2lucy4gDQoNCg0KKiA8Zm9udCBjb2xvciA9ICJibHVlIj4kQyQgY29udHJvbHMgdGhlIHBlbmFsdHkgZm9yIG1pc2NsYXNzaWZpZWQgb3IgbWFyZ2luLXZpb2xhdGluZyBkYXRhIHBvaW50cyBpbiBzb2Z0IG1hcmdpbiBTVk0uPC9mb250Pg0KKiA8Zm9udCBjb2xvciA9ICJibHVlIj5BIGxhcmdlciAkQyQgaW1wb3NlcyBhIGhpZ2hlciBwZW5hbHR5IGZvciBtaXNjbGFzc2lmaWNhdGlvbnMsIGxlYWRpbmcgdG8gYSBuYXJyb3dlciBtYXJnaW4gYW5kIHN0cmljdGVyIGNsYXNzaWZpY2F0aW9uIChjbG9zZXIgdG8gaGFyZCBtYXJnaW4gU1ZNKS48L2ZvbnQ+DQoqIDxmb250IGNvbG9yID0gImJsdWUiPkEgc21hbGxlciAkQyQgYWxsb3dzIG1vcmUgbWlzY2xhc3NpZmljYXRpb25zLCByZXN1bHRpbmcgaW4gYSB3aWRlciBtYXJnaW4gYW5kIGEgbW9yZSBmbGV4aWJsZSBtb2RlbC48L2ZvbnQ+DQoNCg0KUHJvcGVyIHR1bmluZyBvZiAkQyQgaXMgY3J1Y2lhbCBiZWNhdXNlIGl0IGRpcmVjdGx5IGluZmx1ZW5jZXMgdGhlIHRyYWRlLW9mZiBiZXR3ZWVuIG1heGltaXppbmcgdGhlIG1hcmdpbiBhbmQgbWluaW1pemluZyBjbGFzc2lmaWNhdGlvbiBlcnJvcnMuDQoNCg0KDQojIyAkXG51JCAtIENsYXNzaWZpY2F0aW9uDQoNClVubGlrZSBDLWNsYXNzaWZpY2F0aW9uIFNWTSBpbiB3aGljaCB0aGUgdHJhZGUtb2ZmIGJldHdlZW4gbWF4aW1pemluZyB0aGUgbWFyZ2luIGFuZCBtaW5pbWl6aW5nIG1pc2NsYXNzaWZpY2F0aW9uIGVycm9ycyBpcyBjb250cm9sbGVkIGJ5IHRoZSByZWd1bGFyaXphdGlvbiBwYXJhbWV0ZXIgJEMkLCBJbiAkXG51JC1TVk0sIHRoZSB0cmFkZS1vZmYgaXMgY29udHJvbGxlZCBieSB0aGUgcGFyYW1ldGVyICRcbnUkLiBUaGUgb2JqZWN0aXZlIGZ1bmN0aW9uIGlzIGRlZmluZWQgYXMNCg0KJCQNClxtaW5fe1xtYXRoYmZ7d30sIGIsIFxtYXRoYmZ7XHhpfSwgXHJob30gXGxlZnQoIHx8XG1hdGhiZnt3fXx8XjIgLSBcbnUgXHJobyArXGZyYWN7MX17Tn1cc3VtX3tpPTF9Xk4gXHhpX2lccmlnaHQpDQokJA0Kc3ViamVjdHMgY29uc3RyYWludHMNCg0KJCQNCnlfaShcbWF0aGJme3d9XlQgXG1hdGhiZnt4fV9pICsgYikgXGdlIFxyaG8gLSBcbWF0aGJme1x4aX1faSwgXCBcIFxtYXRoYmZ7XHhpfV9pIFxnZSAwLCBcIFwgXHRleHR7YW5kfSBcIFwgXHJobyA+IDAsDQokJA0KDQp3aGVyZSANCg0KKiAkfHxcbWF0aGJme3d9fHxeMiQgcmVmbGVjdCB0aGUgbWFyZ2luIGFzIGluIEMtU1ZNLA0KKiAkLVxudSBccmhvJCBhZGp1c3RzIHRoZSBtYXJnaW4gIHdpZHRoICRccmhvJCwNCiogJC1cc3VtX3tpPTF9Xk5ceGlfaS9OJCBwZW5hbGl6ZXMgbWlzY2xhc3NpZmljYXRpb25zIChzbGFjayB2YXJpYWJsZXMgJFx4aV9pJCkuDQoNCiRcbnUkIGlzIHRoZSBoeXBlcnBhcmFtZXRlciBpbiAkXG51JC1jbGFzc2lmaWNhdGlvbiBTVk0gdGhhdCBuZWVkcyB0byBiZSB0dW5lZCB0aHJvdWdoIHZhcmlvdXMgbWV0aG9kcyBpbmNsdWRpbmcgY3Jvc3MtdmFsaWRhdGlvbi4gSXQgY29udHJvbHMgdGhlIGZyYWN0aW9uIG9mIG1hcmdpbiBlcnJvcnMgYW5kIHN1cHBvcnQgdmVjdG9ycy4NCg0KKiAkXG51IFxpbiAoMCwxXSQNCiogQSAqKnNtYWxsICRcbnUkKiogcmVzdWx0cyBpbiBhIHdpZGVyIG1hcmdpbiBidXQgYWxsb3dzIG1vcmUgbWlzY2xhc3NpZmljYXRpb25zLg0KKiBBICoqbGFyZ2UgJFxudSQqKiByZXN1bHRzIGluIGEgbmFycm93ZXIgbWFyZ2luIGJ1dCBhbGxvd3MgZmV3ZXIgbWlzY2xhc3NpZmljYXRpb25zLg0KDQoNCg0KIyMgQy1TVk0gdi5zLiAkXG51JC1TVk0NCg0KVGhlcmUgaXMgYSB0aGVvcmV0aWNhbCByZWxhdGlvbnNoaXAgYmV0d2VlbiAkQyQtU1ZNIGFuZCAkXG51JC1TVk0uIEZvciBhIGdpdmVuIGRhdGFzZXQsIHRoZXJlIGV4aXN0cyBhIG1hcHBpbmcgYmV0d2VlbiAkQyQgYW5kICRcbnUkIHN1Y2ggdGhhdCB0aGUgc29sdXRpb25zIG9mIEMtU1ZNIGFuZCAkXG51JC1TVk0gYXJlIGVxdWl2YWxlbnQuIEhvd2V2ZXIsIHRoaXMgbWFwcGluZyBkZXBlbmRzIG9uIHRoZSBkYXRhc2V0IGFuZCBpcyBub3Qgc3RyYWlnaHRmb3J3YXJkIHRvIGNvbXB1dGUuDQoNCkMtU1ZNIGFuZCAkXG51JC1TVk0gY2FuIHByb2R1Y2UgdGhlIHNhbWUgcmVzdWx0IGlmOg0KDQoqIFRoZSBwYXJhbWV0ZXJzIEMgYW5kICRcbnUkIGFyZSBjaG9zZW4gc3VjaCB0aGF0IHRoZXkgY29ycmVzcG9uZCB0byB0aGUgc2FtZSB0cmFkZS1vZmYgYmV0d2VlbiBtYXJnaW4gc2l6ZSBhbmQgY2xhc3NpZmljYXRpb24gZXJyb3JzLg0KDQoqIFRoZSBkYXRhc2V0IGFuZCBrZXJuZWwgYXJlIHRoZSBzYW1lLg0KDQoqIFRoZSBvcHRpbWl6YXRpb24gYWxnb3JpdGhtIGNvbnZlcmdlcyB0byB0aGUgc2FtZSBzb2x1dGlvbi4NCg0KSW4gcHJhY3RpY2UsIHRoaXMgZXF1aXZhbGVuY2UgaXMgcmFyZWx5IGV4cGxvaXRlZCBiZWNhdXNlICRcbnUkLVNWTSBwcm92aWRlcyBhIG1vcmUgaW50dWl0aXZlIHdheSB0byBjb250cm9sIHRoZSBmcmFjdGlvbiBvZiBzdXBwb3J0IHZlY3RvcnMgYW5kIGVycm9ycywgd2hpbGUgQy1TVk0gcmVxdWlyZXMgdHVuaW5nIEMgdGhyb3VnaCBjcm9zcy12YWxpZGF0aW9uIG9yIG90aGVyIG1ldGhvZHMuDQoNCg0KDQoNCg0KRm9yIHRoZSBjb252ZW5pZW5jZSBvZiBjb21wYXJpc29uLCB3ZSBtYWtlIHRoZSBmb2xsb3dpbmcgdGFibGUgdG8gc2hvdyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0d28gc3VwcG9ydCB2ZWN0b3IgbWFjaGluZXMuDQoNCg0KfCAJfCBDLUNsYXNzaWZpY2F0aW9uCXwgJFxudSQtQ2xhc3NpZmljYXRpb24gfA0KfDotLS0tLS0tLS0tLS0tfDotLS0tLS0tLS0tLS0tLS0tLS0tLS18Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLS18DQp8SHlwZXJwYXJhbWV0ZXIJfCBVc2VzICRDJCAoY29zdCBwYXJhbWV0ZXIpLgl8IFVzZXMgJFxudSQgKG51IHBhcmFtZXRlcikufA0KfEludGVycHJldGF0aW9uCXwgJEMkIGNvbnRyb2xzIHRoZSBwZW5hbHR5IGZvciBtaXNzLWNsYXNzaWZpY2F0aW9ucy4gfCAkXG51JCBjb250cm9scyB0aGUgZnJhY3Rpb24gb2Ygc3VwcG9ydCB2ZWN0b3JzIGFuZCBtYXJnaW4gZXJyb3JzLnwNCnxSYW5nZQl8IEMgY2FuIHRha2UgYW55IHBvc2l0aXZlIHZhbHVlICh0eXBpY2FsbHkgJEM+MCQpLiB8CSRcbnUkIHJhbmdlcyBiZXR3ZWVuIDAgYW5kIDEgKCQwPFxudSBcbGUgMSQpLg0KfEZvY3VzCXwgRm9jdXNlcyBvbiBtaW5pbWl6aW5nIGNsYXNzaWZpY2F0aW9uIGVycm9ycy4gfAlGb2N1c2VzIG9uIGNvbnRyb2xsaW5nIHRoZSBmcmFjdGlvbiBvZiBzdXBwb3J0IHZlY3RvcnMgYW5kIG1hcmdpbiBlcnJvcnMufA0KfCBNYXJnaW4gQ29udHJvbCB8CUZpeGVkIG1hcmdpbnwgCUFkYXB0aXZlIG1hcmdpbiAoJFxyaG8kKSB8DQp8SW50ZXJwcmV0YWJpbGl0eSB8CUxlc3MgaW50dWl0aXZlIHwJTW9yZSBpbnR1aXRpdmUgfA0KfEVhc2Ugb2YgVHVuaW5nIHwJUmVxdWlyZXMgY2FyZWZ1bCB0dW5pbmcgb2YgQyB0byBiYWxhbmNlIGJpYXMgYW5kIHZhcmlhbmNlLnwJRWFzaWVyIHRvIGludGVycHJldCwgYXMgJFxudSQgZGlyZWN0bHkgcmVsYXRlcyB0byB0aGUgZnJhY3Rpb24gb2Ygc3VwcG9ydCB2ZWN0b3JzLnwNCnwgVXNlIENhc2UgfAlHZW5lcmFsLXB1cnBvc2UgfAlUYXNrcyByZXF1aXJpbmcgY29udHJvbCBvdmVyIHN1cHBvcnQgdmVjdG9ycyB8DQoNCg0KJFxudSQtU1ZNIGlzIGEgcG93ZXJmdWwgYW5kIGludGVycHJldGFibGUgdmFyaWFudCBvZiBTVk0gdGhhdCBwcm92aWRlcyBleHBsaWNpdCBjb250cm9sIG92ZXIgdGhlIGZyYWN0aW9uIG9mIHN1cHBvcnQgdmVjdG9ycyBhbmQgbWFyZ2luIGVycm9ycy4gSXRzIGludHVpdGl2ZSBwYXJhbWV0ZXJpemF0aW9uIGFuZCBhZGFwdGl2ZSBtYXJnaW4gbWFrZSBpdCBhIHZhbHVhYmxlIHRvb2wgZm9yIGNsYXNzaWZpY2F0aW9uLCByZWdyZXNzaW9uLCBhbmQgb3V0bGllciBkZXRlY3Rpb24gdGFza3MuIA0KDQoNClwNCg0KIyMgU1ZNIHdpdGggUg0KDQpTdXBwb3J0IFZlY3RvciBNYWNoaW5lcyAoU1ZNKSBhcmUgYSBwb3B1bGFyIHNldCBvZiBtYWNoaW5lIGxlYXJuaW5nIGFsZ29yaXRobXMgdXNlZCBmb3IgY2xhc3NpZmljYXRpb24sIHJlZ3Jlc3Npb24sIGFuZCBvdXRsaWVyIGRldGVjdGlvbi4gSW4gUiwgc2V2ZXJhbCBsaWJyYXJpZXMgcHJvdmlkZSBpbXBsZW1lbnRhdGlvbnMgb2YgU1ZNLCBlYWNoIHdpdGggaXRzIG93biBmZWF0dXJlcyBhbmQgY2FwYWJpbGl0aWVzLiBXZSB3aWxsIHVzZSB0d28gb2YgdGhlIG1vc3QgY29tbW9ubHkgdXNlZCBsaWJyYXJpZXM6IGBlMTA3MWAgYW5kIGBrZXJubGFiYC4gIEEgcmVjZW50bHkgZGV2ZWxvcGVkIFIgbGlicmFyeSBgY2FyZXRgIGluY2x1ZGVzIHNvbWUgb2YgdGhlIFIgZnVuY3Rpb25zIGluIHRoZSBhZm9yZW1lbnRpb25lZCBsaWJyYXJpZXMgd2l0aCBzb21lIGFkZGl0aW9uYWwgY29udmVuaWVudCBmdW5jdGlvbnMgZm9yIHBlcmZvcm1pbmcgbWFjaGluZSBsZWFybmluZyB0YXNrcy4gDQoNCiogKiplMTA3MSoqOiBHZW5lcmFsLXB1cnBvc2UgU1ZNIGZvciBjbGFzc2lmaWNhdGlvbiBhbmQgcmVncmVzc2lvbiB0YXNrcy4gSXQgaXMgb25lIG9mIHRoZSBtb3N0IHdpZGVseSB1c2VkIHBhY2thZ2VzIGZvciBTVk0gaW4gUiB0aGF0IFN1cHBvcnRzIHZhcmlvdXMga2VybmVsIGZ1bmN0aW9ucyAobGluZWFyLCBwb2x5bm9taWFsLCByYWRpYWwgYmFzaXMsIHNpZ21vaWQpIGFuZCBwcm92aWRlcyB0b29scyBmb3IgbW9kZWwgdHVuaW5nIGFuZCBjcm9zcy12YWxpZGF0aW9uLg0KICArIGBzdm0oKWA6IEZpdHMgYW4gU1ZNIG1vZGVsIGZvciBjbGFzc2lmaWNhdGlvbiwgcmVncmVzc2lvbiwgb3Igbm92ZWx0eSBkZXRlY3Rpb24uDQogICsgYHR1bmUuc3ZtKClgOiBQZXJmb3JtcyBoeXBlcnBhcmFtZXRlciB0dW5pbmcgKGUuZy4sIGNvc3QsIGdhbW1hKSB1c2luZyBncmlkIHNlYXJjaC4NCg0KDQoqICoqa2VybmxhYioqOiBBZHZhbmNlZCBTVk0gdGFza3Mgd2l0aCBjdXN0b20ga2VybmVscyBvciBzcGVjaWFsaXplZCByZXF1aXJlbWVudHMuIEl0IGlzIGEgY29tcHJlaGVuc2l2ZSBwYWNrYWdlIGZvciBrZXJuZWwtYmFzZWQgbWFjaGluZSBsZWFybmluZywgaW5jbHVkaW5nIFNWTS4gSXQgb2ZmZXJzIGEgd2lkZSByYW5nZSBvZiBrZXJuZWwgZnVuY3Rpb25zIGFuZCBpcyBoaWdobHkgZmxleGlibGUuDQogICsgYGtzdm0oKWA6IEZpdHMgYW4gU1ZNIG1vZGVsIHdpdGggc3VwcG9ydCBmb3IgbXVsdGlwbGUga2VybmVsIHR5cGVzLg0KICArIGBrZXJuZWxNYXRyaXgoKWA6IENvbXB1dGVzIHRoZSBrZXJuZWwgbWF0cml4IGZvciBjdXN0b20ga2VybmVscy4NCg0KKiAqKmNhcmV0Kio6IFN0cmVhbWxpbmVkIFNWTSBtb2RlbGluZyB3aXRoIGF1dG9tYXRlZCB0dW5pbmcgYW5kIGV2YWx1YXRpb24uIEl0IGlzIGEgbWV0YS1wYWNrYWdlIGZvciBtYWNoaW5lIGxlYXJuaW5nIHRoYXQgcHJvdmlkZXMgYSB1bmlmaWVkIGludGVyZmFjZSBmb3IgdmFyaW91cyBtb2RlbHMsIGluY2x1ZGluZyBTVk0uIEl0IHVzZXMgYGUxMDcxYCBvciBga2VybmxhYmAgdW5kZXIgdGhlIGhvb2QgYW5kIHNpbXBsaWZpZXMgbW9kZWwgdHJhaW5pbmcgYW5kIGV2YWx1YXRpb24gYW5kIGludGVncmF0ZXMgd2l0aCBvdGhlciBtYWNoaW5lIGxlYXJuaW5nIHdvcmtmbG93cy4NCiAgKyBgdHJhaW4oKWA6IEZpdHMgYW4gU1ZNIG1vZGVsIHdpdGggaHlwZXJwYXJhbWV0ZXIgdHVuaW5nIGFuZCBjcm9zcy12YWxpZGF0aW9uLg0KDQoNCg0KDQoNCg0KDQo=